blob: 188ba82f03dcb404d0197cbf318f3a13819cff85 [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"
Rayan Kansoe147def2019-07-22 09:56:3511#include "base/optional.h"
Rayan Kanso5e2ff0e2019-09-04 10:33:1012#include "base/stl_util.h"
Rayan Kanso24f7d412019-07-11 10:09:3013#include "base/task/post_task.h"
Rayan Kanso296eb3d2019-06-26 11:32:0414#include "base/time/time.h"
Rayan Kanso837b7952019-07-01 10:31:2915#include "content/browser/background_fetch/storage/image_helpers.h"
Rayan Kanso296eb3d2019-06-26 11:32:0416#include "content/browser/content_index/content_index.pb.h"
Rayan Kanso9f3944a2019-07-30 12:18:0717#include "content/browser/content_index/content_index_metrics.h"
Rayan Kanso03a847b2019-06-27 21:00:0918#include "content/public/browser/browser_context.h"
Rayan Kanso24f7d412019-07-11 10:09:3019#include "content/public/browser/browser_task_traits.h"
Rayan Kanso296eb3d2019-06-26 11:32:0420#include "content/public/browser/browser_thread.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
Rayan Kansoe147def2019-07-22 09:56:35105base::Optional<ContentIndexEntry> EntryFromSerializedProto(
106 int64_t service_worker_registration_id,
107 const std::string& serialized_proto) {
108 proto::ContentEntry entry_proto;
109 if (!entry_proto.ParseFromString(serialized_proto))
110 return base::nullopt;
111
112 GURL launch_url(entry_proto.launch_url());
113 if (!launch_url.is_valid())
114 return base::nullopt;
115
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) {
147 base::PostTask(FROM_HERE, {BrowserThread::UI},
148 base::BindOnce(std::move(callback), error));
149 },
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 Kansob0f54fe2019-08-05 18:59:14177 auto serialized_icons = std::make_unique<proto::SerializedIcons>();
178 proto::SerializedIcons* serialized_icons_ptr = serialized_icons.get();
179
180 auto barrier_closure = base::BarrierClosure(
181 icons.size(),
182 base::BindOnce(&ContentIndexDatabase::DidSerializeIcons,
Matt Falkenhagen105efb822019-08-29 20:49:17183 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kansob0f54fe2019-08-05 18:59:14184 service_worker_registration_id, origin,
185 std::move(description), launch_url,
186 std::move(serialized_icons), std::move(callback)));
187
188 for (const auto& icon : icons) {
189 SerializeIcon(icon,
190 base::BindOnce(
191 [](base::OnceClosure done_closure,
192 proto::SerializedIcons* icons, std::string icon) {
193 icons->add_icons()->set_icon(std::move(icon));
194 std::move(done_closure).Run();
195 },
196 barrier_closure, serialized_icons_ptr));
197 }
Rayan Kanso837b7952019-07-01 10:31:29198}
199
Rayan Kansob0f54fe2019-08-05 18:59:14200void ContentIndexDatabase::DidSerializeIcons(
Rayan Kanso837b7952019-07-01 10:31:29201 int64_t service_worker_registration_id,
202 const url::Origin& origin,
203 blink::mojom::ContentDescriptionPtr description,
Rayan Kanso37c08702019-07-12 17:07:41204 const GURL& launch_url,
Rayan Kansob0f54fe2019-08-05 18:59:14205 std::unique_ptr<proto::SerializedIcons> serialized_icons,
206 blink::mojom::ContentIndexService::AddCallback callback) {
Rayan Kanso03a847b2019-06-27 21:00:09207 base::Time entry_time = base::Time::Now();
Rayan Kanso837b7952019-07-01 10:31:29208 std::string entry_key = EntryKey(description->id);
Rayan Kansob0f54fe2019-08-05 18:59:14209 std::string icon_key = IconsKey(description->id);
Rayan Kanso837b7952019-07-01 10:31:29210 std::string entry_value =
Rayan Kanso37c08702019-07-12 17:07:41211 CreateSerializedContentEntry(*description, launch_url, entry_time);
Rayan Kansob0f54fe2019-08-05 18:59:14212 std::string icons_value = serialized_icons->SerializeAsString();
Rayan Kanso296eb3d2019-06-26 11:32:04213
Rayan Kanso03a847b2019-06-27 21:00:09214 // Entry to pass over to the provider.
215 ContentIndexEntry entry(service_worker_registration_id,
Rayan Kanso37c08702019-07-12 17:07:41216 std::move(description), launch_url, entry_time);
Rayan Kanso03a847b2019-06-27 21:00:09217
Rayan Kanso296eb3d2019-06-26 11:32:04218 service_worker_context_->StoreRegistrationUserData(
Rayan Kansod33e2772019-06-27 16:52:41219 service_worker_registration_id, origin.GetURL(),
Rayan Kanso837b7952019-07-01 10:31:29220 {{std::move(entry_key), std::move(entry_value)},
Rayan Kansob0f54fe2019-08-05 18:59:14221 {std::move(icon_key), std::move(icons_value)}},
Rayan Kanso296eb3d2019-06-26 11:32:04222 base::BindOnce(&ContentIndexDatabase::DidAddEntry,
Matt Falkenhagen105efb822019-08-29 20:49:17223 weak_ptr_factory_core_.GetWeakPtr(), std::move(callback),
Rayan Kanso03a847b2019-06-27 21:00:09224 std::move(entry)));
Rayan Kanso296eb3d2019-06-26 11:32:04225}
226
227void ContentIndexDatabase::DidAddEntry(
228 blink::mojom::ContentIndexService::AddCallback callback,
Rayan Kanso03a847b2019-06-27 21:00:09229 ContentIndexEntry entry,
Rayan Kanso296eb3d2019-06-26 11:32:04230 blink::ServiceWorkerStatusCode status) {
Rayan Kanso9f3944a2019-07-30 12:18:07231 content_index::RecordDatabaseOperationStatus("Add", status);
232
Rayan Kanso03a847b2019-06-27 21:00:09233 if (status != blink::ServiceWorkerStatusCode::kOk) {
Rayan Kanso296eb3d2019-06-26 11:32:04234 std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR);
Rayan Kanso03a847b2019-06-27 21:00:09235 return;
236 }
237
238 std::move(callback).Run(blink::mojom::ContentIndexError::NONE);
239
Rayan Kanso24f7d412019-07-11 10:09:30240 std::vector<ContentIndexEntry> entries;
241 entries.push_back(std::move(entry));
Sami Kyostila8e4d5a92019-08-02 12:45:05242 base::PostTask(
Rayan Kanso24f7d412019-07-11 10:09:30243 FROM_HERE, {BrowserThread::UI},
244 base::BindOnce(&ContentIndexDatabase::NotifyProviderContentAdded,
245 weak_ptr_factory_ui_.GetWeakPtr(), std::move(entries)));
Rayan Kanso296eb3d2019-06-26 11:32:04246}
247
248void ContentIndexDatabase::DeleteEntry(
249 int64_t service_worker_registration_id,
Rayan Kansoa42c3caf2019-07-19 17:21:20250 const url::Origin& origin,
Rayan Kanso296eb3d2019-06-26 11:32:04251 const std::string& entry_id,
252 blink::mojom::ContentIndexService::DeleteCallback callback) {
Rayan Kanso7806f692019-08-21 12:30:44253 DCHECK_CURRENTLY_ON(BrowserThread::UI);
254
255 auto wrapped_callback = base::BindOnce(
256 [](blink::mojom::ContentIndexService::DeleteCallback callback,
257 blink::mojom::ContentIndexError error) {
258 base::PostTask(FROM_HERE, {BrowserThread::UI},
259 base::BindOnce(std::move(callback), error));
260 },
261 std::move(callback));
262
Matt Falkenhagen105efb822019-08-29 20:49:17263 RunOrPostTaskOnThread(
264 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
265 base::BindOnce(&ContentIndexDatabase::DeleteEntryOnCoreThread,
266 weak_ptr_factory_core_.GetWeakPtr(),
267 service_worker_registration_id, origin, entry_id,
268 std::move(wrapped_callback)));
Rayan Kanso7806f692019-08-21 12:30:44269}
270
Matt Falkenhagen105efb822019-08-29 20:49:17271void ContentIndexDatabase::DeleteEntryOnCoreThread(
Rayan Kanso7806f692019-08-21 12:30:44272 int64_t service_worker_registration_id,
273 const url::Origin& origin,
274 const std::string& entry_id,
275 blink::mojom::ContentIndexService::DeleteCallback callback) {
Matt Falkenhagen105efb822019-08-29 20:49:17276 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44277
Rayan Kanso296eb3d2019-06-26 11:32:04278 service_worker_context_->ClearRegistrationUserData(
Rayan Kansob0f54fe2019-08-05 18:59:14279 service_worker_registration_id, {EntryKey(entry_id), IconsKey(entry_id)},
Rayan Kanso24f7d412019-07-11 10:09:30280 base::BindOnce(&ContentIndexDatabase::DidDeleteEntry,
Matt Falkenhagen105efb822019-08-29 20:49:17281 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kansoa42c3caf2019-07-19 17:21:20282 service_worker_registration_id, origin, entry_id,
Rayan Kanso24f7d412019-07-11 10:09:30283 std::move(callback)));
Rayan Kanso296eb3d2019-06-26 11:32:04284}
285
286void ContentIndexDatabase::DidDeleteEntry(
Rayan Kanso03a847b2019-06-27 21:00:09287 int64_t service_worker_registration_id,
Rayan Kansoa42c3caf2019-07-19 17:21:20288 const url::Origin& origin,
Rayan Kanso03a847b2019-06-27 21:00:09289 const std::string& entry_id,
Rayan Kanso296eb3d2019-06-26 11:32:04290 blink::mojom::ContentIndexService::DeleteCallback callback,
291 blink::ServiceWorkerStatusCode status) {
Rayan Kanso9f3944a2019-07-30 12:18:07292 content_index::RecordDatabaseOperationStatus("Delete", status);
293
Rayan Kanso03a847b2019-06-27 21:00:09294 if (status != blink::ServiceWorkerStatusCode::kOk) {
Rayan Kanso296eb3d2019-06-26 11:32:04295 std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR);
Rayan Kanso03a847b2019-06-27 21:00:09296 return;
297 }
298
299 std::move(callback).Run(blink::mojom::ContentIndexError::NONE);
Rayan Kanso24f7d412019-07-11 10:09:30300
Sami Kyostila8e4d5a92019-08-02 12:45:05301 base::PostTask(
Rayan Kanso24f7d412019-07-11 10:09:30302 FROM_HERE, {BrowserThread::UI},
303 base::BindOnce(&ContentIndexDatabase::NotifyProviderContentDeleted,
304 weak_ptr_factory_ui_.GetWeakPtr(),
Rayan Kansoa42c3caf2019-07-19 17:21:20305 service_worker_registration_id, origin, entry_id));
Rayan Kanso296eb3d2019-06-26 11:32:04306}
307
308void ContentIndexDatabase::GetDescriptions(
309 int64_t service_worker_registration_id,
310 blink::mojom::ContentIndexService::GetDescriptionsCallback callback) {
Rayan Kanso7806f692019-08-21 12:30:44311 DCHECK_CURRENTLY_ON(BrowserThread::UI);
312
313 auto wrapped_callback = base::BindOnce(
314 [](blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
315 blink::mojom::ContentIndexError error,
316 std::vector<blink::mojom::ContentDescriptionPtr> descriptions) {
317 base::PostTask(FROM_HERE, {BrowserThread::UI},
318 base::BindOnce(std::move(callback), error,
319 std::move(descriptions)));
320 },
321 std::move(callback));
322
Matt Falkenhagen105efb822019-08-29 20:49:17323 RunOrPostTaskOnThread(
324 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
325 base::BindOnce(&ContentIndexDatabase::GetDescriptionsOnCoreThread,
326 weak_ptr_factory_core_.GetWeakPtr(),
327 service_worker_registration_id,
328 std::move(wrapped_callback)));
Rayan Kanso7806f692019-08-21 12:30:44329}
330
Matt Falkenhagen105efb822019-08-29 20:49:17331void ContentIndexDatabase::GetDescriptionsOnCoreThread(
Rayan Kanso7806f692019-08-21 12:30:44332 int64_t service_worker_registration_id,
333 blink::mojom::ContentIndexService::GetDescriptionsCallback callback) {
Matt Falkenhagen105efb822019-08-29 20:49:17334 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44335
Rayan Kanso296eb3d2019-06-26 11:32:04336 service_worker_context_->GetRegistrationUserDataByKeyPrefix(
337 service_worker_registration_id, kEntryPrefix,
338 base::BindOnce(&ContentIndexDatabase::DidGetDescriptions,
Rayan Kanso5e2ff0e2019-09-04 10:33:10339 weak_ptr_factory_core_.GetWeakPtr(),
340 service_worker_registration_id, std::move(callback)));
Rayan Kanso296eb3d2019-06-26 11:32:04341}
342
343void ContentIndexDatabase::DidGetDescriptions(
Rayan Kanso5e2ff0e2019-09-04 10:33:10344 int64_t service_worker_registration_id,
Rayan Kanso296eb3d2019-06-26 11:32:04345 blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
346 const std::vector<std::string>& data,
347 blink::ServiceWorkerStatusCode status) {
Rayan Kanso9f3944a2019-07-30 12:18:07348 content_index::RecordDatabaseOperationStatus("GetDescriptions", status);
349
Rayan Kanso296eb3d2019-06-26 11:32:04350 if (status == blink::ServiceWorkerStatusCode::kErrorNotFound) {
351 std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
352 /* descriptions= */ {});
353 return;
354 } else if (status != blink::ServiceWorkerStatusCode::kOk) {
355 std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
356 /* descriptions= */ {});
357 return;
358 }
359
360 std::vector<blink::mojom::ContentDescriptionPtr> descriptions;
361 descriptions.reserve(data.size());
362
Rayan Kanso296eb3d2019-06-26 11:32:04363 for (const auto& serialized_entry : data) {
364 proto::ContentEntry entry;
365 if (!entry.ParseFromString(serialized_entry)) {
Rayan Kanso5e2ff0e2019-09-04 10:33:10366 ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
Rayan Kanso296eb3d2019-06-26 11:32:04367 std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
368 /* descriptions= */ {});
369 return;
370 }
371
372 auto description = DescriptionFromProto(entry.description());
373 if (!description) {
Rayan Kanso5e2ff0e2019-09-04 10:33:10374 // Clear entry data.
375 service_worker_context_->ClearRegistrationUserData(
376 service_worker_registration_id,
377 {EntryKey(entry.description().id()),
378 IconsKey(entry.description().id())},
379 base::BindOnce(&content_index::RecordDatabaseOperationStatus,
380 "ClearCorruptedData"));
381 continue;
Rayan Kanso296eb3d2019-06-26 11:32:04382 }
383
384 descriptions.push_back(std::move(description));
385 }
386
387 std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
388 std::move(descriptions));
389}
390
Rayan Kansob0f54fe2019-08-05 18:59:14391void ContentIndexDatabase::GetIcons(
Rayan Kanso03a847b2019-06-27 21:00:09392 int64_t service_worker_registration_id,
393 const std::string& description_id,
Rayan Kansob0f54fe2019-08-05 18:59:14394 ContentIndexContext::GetIconsCallback callback) {
Rayan Kanso7806f692019-08-21 12:30:44395 DCHECK_CURRENTLY_ON(BrowserThread::UI);
396
397 auto wrapped_callback = base::BindOnce(
398 [](ContentIndexContext::GetIconsCallback callback,
399 std::vector<SkBitmap> icons) {
400 base::PostTask(FROM_HERE, {BrowserThread::UI},
401 base::BindOnce(std::move(callback), std::move(icons)));
402 },
403 std::move(callback));
404
Matt Falkenhagen105efb822019-08-29 20:49:17405 RunOrPostTaskOnThread(
406 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
407 base::BindOnce(&ContentIndexDatabase::GetIconsOnCoreThread,
408 weak_ptr_factory_core_.GetWeakPtr(),
409 service_worker_registration_id, description_id,
410 std::move(wrapped_callback)));
Rayan Kanso7806f692019-08-21 12:30:44411}
412
Matt Falkenhagen105efb822019-08-29 20:49:17413void ContentIndexDatabase::GetIconsOnCoreThread(
Rayan Kanso7806f692019-08-21 12:30:44414 int64_t service_worker_registration_id,
415 const std::string& description_id,
416 ContentIndexContext::GetIconsCallback callback) {
Matt Falkenhagen105efb822019-08-29 20:49:17417 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso24f7d412019-07-11 10:09:30418
Rayan Kanso837b7952019-07-01 10:31:29419 service_worker_context_->GetRegistrationUserData(
Rayan Kansob0f54fe2019-08-05 18:59:14420 service_worker_registration_id, {IconsKey(description_id)},
421 base::BindOnce(&ContentIndexDatabase::DidGetSerializedIcons,
Rayan Kanso5e2ff0e2019-09-04 10:33:10422 weak_ptr_factory_core_.GetWeakPtr(),
423 service_worker_registration_id, std::move(callback)));
Rayan Kanso837b7952019-07-01 10:31:29424}
425
Rayan Kansob0f54fe2019-08-05 18:59:14426void ContentIndexDatabase::DidGetSerializedIcons(
Rayan Kanso5e2ff0e2019-09-04 10:33:10427 int64_t service_worker_registration_id,
Rayan Kansob0f54fe2019-08-05 18:59:14428 ContentIndexContext::GetIconsCallback callback,
Rayan Kanso837b7952019-07-01 10:31:29429 const std::vector<std::string>& data,
430 blink::ServiceWorkerStatusCode status) {
Matt Falkenhagen105efb822019-08-29 20:49:17431 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kansob0f54fe2019-08-05 18:59:14432
Rayan Kanso9f3944a2019-07-30 12:18:07433 content_index::RecordDatabaseOperationStatus("GetIcon", status);
434
Rayan Kanso837b7952019-07-01 10:31:29435 if (status != blink::ServiceWorkerStatusCode::kOk || data.empty()) {
Rayan Kansob0f54fe2019-08-05 18:59:14436 std::move(callback).Run({});
Rayan Kanso837b7952019-07-01 10:31:29437 return;
438 }
439
440 DCHECK_EQ(data.size(), 1u);
Rayan Kansob0f54fe2019-08-05 18:59:14441 proto::SerializedIcons serialized_icons;
442 if (!serialized_icons.ParseFromString(data.front())) {
Rayan Kanso5e2ff0e2019-09-04 10:33:10443 ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
Rayan Kansob0f54fe2019-08-05 18:59:14444 std::move(callback).Run({});
445 return;
446 }
Rayan Kanso837b7952019-07-01 10:31:29447
Rayan Kansob0f54fe2019-08-05 18:59:14448 if (serialized_icons.icons_size() == 0u) {
449 // There are no icons.
450 std::move(callback).Run({});
451 return;
452 }
453
454 auto icons = std::make_unique<std::vector<SkBitmap>>();
455 std::vector<SkBitmap>* icons_ptr = icons.get();
456
457 auto barrier_closure = base::BarrierClosure(
458 serialized_icons.icons_size(),
459 base::BindOnce(&ContentIndexDatabase::DidDeserializeIcons,
Matt Falkenhagen105efb822019-08-29 20:49:17460 weak_ptr_factory_core_.GetWeakPtr(), std::move(callback),
Rayan Kansob0f54fe2019-08-05 18:59:14461 std::move(icons)));
462
463 for (auto& serialized_icon : *serialized_icons.mutable_icons()) {
464 DeserializeIcon(base::WrapUnique(serialized_icon.release_icon()),
465 base::BindOnce(
466 [](base::OnceClosure done_closure,
467 std::vector<SkBitmap>* icons, SkBitmap icon) {
468 icons->push_back(std::move(icon));
469 std::move(done_closure).Run();
470 },
471 barrier_closure, icons_ptr));
472 }
473}
474
475void ContentIndexDatabase::DidDeserializeIcons(
476 ContentIndexContext::GetIconsCallback callback,
477 std::unique_ptr<std::vector<SkBitmap>> icons) {
Matt Falkenhagen105efb822019-08-29 20:49:17478 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kansob0f54fe2019-08-05 18:59:14479
Matt Falkenhagen105efb822019-08-29 20:49:17480 RunOrPostTaskOnThread(FROM_HERE, BrowserThread::UI,
481 base::BindOnce(std::move(callback), std::move(*icons)));
Rayan Kanso03a847b2019-06-27 21:00:09482}
483
Rayan Kansoe147def2019-07-22 09:56:35484void ContentIndexDatabase::GetAllEntries(
485 ContentIndexContext::GetAllEntriesCallback callback) {
Rayan Kanso7806f692019-08-21 12:30:44486 DCHECK_CURRENTLY_ON(BrowserThread::UI);
487
488 auto wrapped_callback = base::BindOnce(
489 [](ContentIndexContext::GetAllEntriesCallback callback,
490 blink::mojom::ContentIndexError error,
491 std::vector<ContentIndexEntry> entries) {
492 base::PostTask(
493 FROM_HERE, {BrowserThread::UI},
494 base::BindOnce(std::move(callback), error, std::move(entries)));
495 },
496 std::move(callback));
497
Matt Falkenhagen105efb822019-08-29 20:49:17498 RunOrPostTaskOnThread(
499 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
500 base::BindOnce(&ContentIndexDatabase::GetAllEntriesOnCoreThread,
501 weak_ptr_factory_core_.GetWeakPtr(),
502 std::move(wrapped_callback)));
Rayan Kanso7806f692019-08-21 12:30:44503}
504
Matt Falkenhagen105efb822019-08-29 20:49:17505void ContentIndexDatabase::GetAllEntriesOnCoreThread(
Rayan Kanso7806f692019-08-21 12:30:44506 ContentIndexContext::GetAllEntriesCallback callback) {
Matt Falkenhagen105efb822019-08-29 20:49:17507 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kansoe147def2019-07-22 09:56:35508
509 service_worker_context_->GetUserDataForAllRegistrationsByKeyPrefix(
510 kEntryPrefix,
511 base::BindOnce(&ContentIndexDatabase::DidGetEntries,
Matt Falkenhagen105efb822019-08-29 20:49:17512 weak_ptr_factory_core_.GetWeakPtr(), std::move(callback)));
Rayan Kansoe147def2019-07-22 09:56:35513}
514
515void ContentIndexDatabase::DidGetEntries(
516 ContentIndexContext::GetAllEntriesCallback callback,
517 const std::vector<std::pair<int64_t, std::string>>& user_data,
518 blink::ServiceWorkerStatusCode status) {
Rayan Kanso9f3944a2019-07-30 12:18:07519 content_index::RecordDatabaseOperationStatus("GetAllEntries", status);
520
Rayan Kansoe147def2019-07-22 09:56:35521 if (status != blink::ServiceWorkerStatusCode::kOk) {
Rayan Kansoe147def2019-07-22 09:56:35522 std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
523 /* entries= */ {});
524 return;
525 }
526
527 if (user_data.empty()) {
528 std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
529 /* entries= */ {});
530 return;
531 }
532
533 std::vector<ContentIndexEntry> entries;
534 entries.reserve(user_data.size());
Rayan Kanso5e2ff0e2019-09-04 10:33:10535 std::set<int64_t> corrupted_sw_ids;
Rayan Kansoe147def2019-07-22 09:56:35536
537 for (const auto& ud : user_data) {
538 auto entry = EntryFromSerializedProto(ud.first, ud.second);
539 if (!entry) {
Rayan Kanso5e2ff0e2019-09-04 10:33:10540 corrupted_sw_ids.insert(ud.first);
541 continue;
Rayan Kansoe147def2019-07-22 09:56:35542 }
543
544 entries.emplace_back(std::move(*entry));
545 }
546
Rayan Kanso5e2ff0e2019-09-04 10:33:10547 if (!corrupted_sw_ids.empty()) {
548 // Remove soon-to-be-deleted entries.
549 base::EraseIf(entries, [&corrupted_sw_ids](const auto& entry) {
550 return corrupted_sw_ids.count(entry.service_worker_registration_id);
551 });
552
553 for (int64_t service_worker_registration_id : corrupted_sw_ids)
554 ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
555 }
556
Rayan Kansoe147def2019-07-22 09:56:35557 std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
558 std::move(entries));
559}
560
561void ContentIndexDatabase::GetEntry(
562 int64_t service_worker_registration_id,
563 const std::string& description_id,
564 ContentIndexContext::GetEntryCallback callback) {
Rayan Kanso7806f692019-08-21 12:30:44565 DCHECK_CURRENTLY_ON(BrowserThread::UI);
566
567 auto wrapped_callback = base::BindOnce(
568 [](ContentIndexContext::GetEntryCallback callback,
569 base::Optional<ContentIndexEntry> entry) {
570 base::PostTask(FROM_HERE, {BrowserThread::UI},
571 base::BindOnce(std::move(callback), std::move(entry)));
572 },
573 std::move(callback));
574
Matt Falkenhagen105efb822019-08-29 20:49:17575 RunOrPostTaskOnThread(
576 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
577 base::BindOnce(&ContentIndexDatabase::GetEntryOnCoreThread,
578 weak_ptr_factory_core_.GetWeakPtr(),
579 service_worker_registration_id, description_id,
580 std::move(wrapped_callback)));
Rayan Kanso7806f692019-08-21 12:30:44581}
582
Matt Falkenhagen105efb822019-08-29 20:49:17583void ContentIndexDatabase::GetEntryOnCoreThread(
Rayan Kanso7806f692019-08-21 12:30:44584 int64_t service_worker_registration_id,
585 const std::string& description_id,
586 ContentIndexContext::GetEntryCallback callback) {
Matt Falkenhagen105efb822019-08-29 20:49:17587 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44588
Rayan Kansoe147def2019-07-22 09:56:35589 service_worker_context_->GetRegistrationUserData(
590 service_worker_registration_id, {EntryKey(description_id)},
591 base::BindOnce(&ContentIndexDatabase::DidGetEntry,
Matt Falkenhagen105efb822019-08-29 20:49:17592 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kansoe147def2019-07-22 09:56:35593 service_worker_registration_id, std::move(callback)));
594}
595
596void ContentIndexDatabase::DidGetEntry(
597 int64_t service_worker_registration_id,
598 ContentIndexContext::GetEntryCallback callback,
599 const std::vector<std::string>& data,
600 blink::ServiceWorkerStatusCode status) {
Rayan Kanso9f3944a2019-07-30 12:18:07601 content_index::RecordDatabaseOperationStatus("GetEntry", status);
602
Rayan Kansoe147def2019-07-22 09:56:35603 if (status != blink::ServiceWorkerStatusCode::kOk) {
Rayan Kansoe147def2019-07-22 09:56:35604 std::move(callback).Run(base::nullopt);
605 return;
606 }
607
608 DCHECK_EQ(data.size(), 1u);
609 std::move(callback).Run(
610 EntryFromSerializedProto(service_worker_registration_id, data.front()));
611}
612
Rayan Kanso5e2ff0e2019-09-04 10:33:10613void ContentIndexDatabase::ClearServiceWorkerDataOnCorruption(
614 int64_t service_worker_registration_id) {
615 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
616
617 service_worker_context_->ClearRegistrationUserDataByKeyPrefixes(
618 service_worker_registration_id, {kEntryPrefix, kIconPrefix},
619 base::BindOnce(&content_index::RecordDatabaseOperationStatus,
620 "ClearCorruptedData"));
621}
622
Rayan Kanso7806f692019-08-21 12:30:44623void ContentIndexDatabase::DeleteItem(int64_t service_worker_registration_id,
624 const url::Origin& origin,
625 const std::string& description_id) {
626 DCHECK_CURRENTLY_ON(BrowserThread::UI);
627
Matt Falkenhagen105efb822019-08-29 20:49:17628 RunOrPostTaskOnThread(
629 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
630 base::BindOnce(&ContentIndexDatabase::DeleteEntryOnCoreThread,
631 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kanso7806f692019-08-21 12:30:44632 service_worker_registration_id, origin, description_id,
633 base::BindOnce(&ContentIndexDatabase::DidDeleteItem,
Matt Falkenhagen105efb822019-08-29 20:49:17634 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kanso7806f692019-08-21 12:30:44635 service_worker_registration_id, origin,
636 description_id)));
637}
638
639void ContentIndexDatabase::DidDeleteItem(
640 int64_t service_worker_registration_id,
641 const url::Origin& origin,
642 const std::string& description_id,
643 blink::mojom::ContentIndexError error) {
Matt Falkenhagen105efb822019-08-29 20:49:17644 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44645
646 if (error != blink::mojom::ContentIndexError::NONE)
647 return;
648
649 service_worker_context_->FindReadyRegistrationForId(
650 service_worker_registration_id, origin.GetURL(),
651 base::BindOnce(&ContentIndexDatabase::StartActiveWorkerForDispatch,
Matt Falkenhagen105efb822019-08-29 20:49:17652 weak_ptr_factory_core_.GetWeakPtr(), description_id));
Rayan Kanso7806f692019-08-21 12:30:44653}
654
655void ContentIndexDatabase::StartActiveWorkerForDispatch(
656 const std::string& description_id,
657 blink::ServiceWorkerStatusCode service_worker_status,
658 scoped_refptr<ServiceWorkerRegistration> registration) {
Matt Falkenhagen105efb822019-08-29 20:49:17659 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44660
661 content_index::RecordDisptachStatus("Find", service_worker_status);
662
663 if (service_worker_status != blink::ServiceWorkerStatusCode::kOk)
664 return;
665
666 ServiceWorkerVersion* service_worker_version = registration->active_version();
667 DCHECK(service_worker_version);
668
669 service_worker_version->RunAfterStartWorker(
670 ServiceWorkerMetrics::EventType::CONTENT_DELETE,
671 base::BindOnce(&ContentIndexDatabase::DeliverMessageToWorker,
Matt Falkenhagen105efb822019-08-29 20:49:17672 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kanso7806f692019-08-21 12:30:44673 base::WrapRefCounted(service_worker_version),
674 std::move(registration), description_id));
675}
676
677void ContentIndexDatabase::DeliverMessageToWorker(
678 scoped_refptr<ServiceWorkerVersion> service_worker,
679 scoped_refptr<ServiceWorkerRegistration> registration,
680 const std::string& description_id,
681 blink::ServiceWorkerStatusCode service_worker_status) {
Matt Falkenhagen105efb822019-08-29 20:49:17682 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44683
684 content_index::RecordDisptachStatus("Start", service_worker_status);
685
686 if (service_worker_status != blink::ServiceWorkerStatusCode::kOk)
687 return;
688
689 // Don't allow DB operations while the `contentdelete` event is firing.
690 // This is to prevent re-registering the deleted content within the event.
691 BlockOrigin(service_worker->script_origin());
692
693 int request_id = service_worker->StartRequest(
694 ServiceWorkerMetrics::EventType::CONTENT_DELETE,
695 base::BindOnce(&ContentIndexDatabase::DidDispatchEvent,
Matt Falkenhagen105efb822019-08-29 20:49:17696 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kanso7806f692019-08-21 12:30:44697 service_worker->script_origin()));
698
699 service_worker->endpoint()->DispatchContentDeleteEvent(
700 description_id, service_worker->CreateSimpleEventCallback(request_id));
701}
702
703void ContentIndexDatabase::DidDispatchEvent(
704 const url::Origin& origin,
705 blink::ServiceWorkerStatusCode service_worker_status) {
Matt Falkenhagen105efb822019-08-29 20:49:17706 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44707
708 content_index::RecordDisptachStatus("Dispatch", service_worker_status);
709 UnblockOrigin(origin);
710}
711
Rayan Kanso394af702019-07-25 12:50:37712void ContentIndexDatabase::BlockOrigin(const url::Origin& origin) {
713 blocked_origins_[origin]++;
714}
715
716void ContentIndexDatabase::UnblockOrigin(const url::Origin& origin) {
717 DCHECK(blocked_origins_.count(origin));
718 auto it = blocked_origins_.find(origin);
719 if (it->second == 1)
720 blocked_origins_.erase(it);
721 else
722 it->second--;
723}
724
Rayan Kansoba075802019-06-28 16:33:48725void ContentIndexDatabase::Shutdown() {
Rayan Kanso24f7d412019-07-11 10:09:30726 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Rayan Kansoba075802019-06-28 16:33:48727
728 provider_ = nullptr;
729}
730
Rayan Kanso24f7d412019-07-11 10:09:30731void ContentIndexDatabase::NotifyProviderContentAdded(
732 std::vector<ContentIndexEntry> entries) {
733 DCHECK_CURRENTLY_ON(BrowserThread::UI);
734
735 if (!provider_)
736 return;
737
Rayan Kansoa42c3caf2019-07-19 17:21:20738 for (auto& entry : entries)
739 provider_->OnContentAdded(std::move(entry));
Rayan Kanso24f7d412019-07-11 10:09:30740}
741
742void ContentIndexDatabase::NotifyProviderContentDeleted(
743 int64_t service_worker_registration_id,
Rayan Kansoa42c3caf2019-07-19 17:21:20744 const url::Origin& origin,
Rayan Kanso24f7d412019-07-11 10:09:30745 const std::string& entry_id) {
746 DCHECK_CURRENTLY_ON(BrowserThread::UI);
747
748 if (!provider_)
749 return;
750
Rayan Kansoa42c3caf2019-07-19 17:21:20751 provider_->OnContentDeleted(service_worker_registration_id, origin, entry_id);
Rayan Kanso24f7d412019-07-11 10:09:30752}
753
Rayan Kanso296eb3d2019-06-26 11:32:04754} // namespace content