1 // Copyright 2016 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/devtools/protocol/storage_handler.h"
6
7 #include <memory>
8 #include <unordered_set>
9 #include <utility>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "base/optional.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "content/browser/cache_storage/cache_storage_context_impl.h"
17 #include "content/browser/devtools/protocol/browser_handler.h"
18 #include "content/browser/devtools/protocol/network.h"
19 #include "content/browser/devtools/protocol/network_handler.h"
20 #include "content/browser/devtools/protocol/storage.h"
21 #include "content/browser/storage_partition_impl.h"
22 #include "content/public/browser/browser_context.h"
23 #include "content/public/browser/browser_task_traits.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/render_process_host.h"
26 #include "content/public/browser/storage_partition.h"
27 #include "storage/browser/quota/quota_client.h"
28 #include "storage/browser/quota/quota_manager.h"
29 #include "storage/browser/quota/quota_manager_proxy.h"
30 #include "storage/browser/quota/quota_override_handle.h"
31 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
32 #include "url/gurl.h"
33 #include "url/origin.h"
34
35 namespace content {
36 namespace protocol {
37
38 using ClearCookiesCallback = Storage::Backend::ClearCookiesCallback;
39 using GetCookiesCallback = Storage::Backend::GetCookiesCallback;
40 using SetCookiesCallback = Storage::Backend::SetCookiesCallback;
41
42 struct UsageListInitializer {
43 const char* type;
44 int64_t blink::mojom::UsageBreakdown::*usage_member;
45 };
46
47 UsageListInitializer initializers[] = {
48 {Storage::StorageTypeEnum::File_systems,
49 &blink::mojom::UsageBreakdown::fileSystem},
50 {Storage::StorageTypeEnum::Websql, &blink::mojom::UsageBreakdown::webSql},
51 {Storage::StorageTypeEnum::Appcache,
52 &blink::mojom::UsageBreakdown::appcache},
53 {Storage::StorageTypeEnum::Indexeddb,
54 &blink::mojom::UsageBreakdown::indexedDatabase},
55 {Storage::StorageTypeEnum::Cache_storage,
56 &blink::mojom::UsageBreakdown::serviceWorkerCache},
57 {Storage::StorageTypeEnum::Service_workers,
58 &blink::mojom::UsageBreakdown::serviceWorker},
59 };
60
61 namespace {
62
ReportUsageAndQuotaDataOnUIThread(std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback,blink::mojom::QuotaStatusCode code,int64_t usage,int64_t quota,bool is_override_enabled,blink::mojom::UsageBreakdownPtr usage_breakdown)63 void ReportUsageAndQuotaDataOnUIThread(
64 std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback,
65 blink::mojom::QuotaStatusCode code,
66 int64_t usage,
67 int64_t quota,
68 bool is_override_enabled,
69 blink::mojom::UsageBreakdownPtr usage_breakdown) {
70 DCHECK_CURRENTLY_ON(BrowserThread::UI);
71 if (code != blink::mojom::QuotaStatusCode::kOk) {
72 return callback->sendFailure(
73 Response::ServerError("Quota information is not available"));
74 }
75
76 auto usageList = std::make_unique<Array<Storage::UsageForType>>();
77
78 blink::mojom::UsageBreakdown* breakdown_ptr = usage_breakdown.get();
79 for (const auto initializer : initializers) {
80 std::unique_ptr<Storage::UsageForType> entry =
81 Storage::UsageForType::Create()
82 .SetStorageType(initializer.type)
83 .SetUsage(breakdown_ptr->*(initializer.usage_member))
84 .Build();
85 usageList->emplace_back(std::move(entry));
86 }
87
88 callback->sendSuccess(usage, quota, is_override_enabled,
89 std::move(usageList));
90 }
91
GotUsageAndQuotaDataCallback(std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback,blink::mojom::QuotaStatusCode code,int64_t usage,int64_t quota,bool is_override_enabled,blink::mojom::UsageBreakdownPtr usage_breakdown)92 void GotUsageAndQuotaDataCallback(
93 std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback,
94 blink::mojom::QuotaStatusCode code,
95 int64_t usage,
96 int64_t quota,
97 bool is_override_enabled,
98 blink::mojom::UsageBreakdownPtr usage_breakdown) {
99 DCHECK_CURRENTLY_ON(BrowserThread::IO);
100 GetUIThreadTaskRunner({})->PostTask(
101 FROM_HERE,
102 base::BindOnce(ReportUsageAndQuotaDataOnUIThread, std::move(callback),
103 code, usage, quota, is_override_enabled,
104 std::move(usage_breakdown)));
105 }
106
GetUsageAndQuotaOnIOThread(storage::QuotaManager * manager,const url::Origin & origin,std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback)107 void GetUsageAndQuotaOnIOThread(
108 storage::QuotaManager* manager,
109 const url::Origin& origin,
110 std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback) {
111 DCHECK_CURRENTLY_ON(BrowserThread::IO);
112 manager->GetUsageAndQuotaForDevtools(
113 origin, blink::mojom::StorageType::kTemporary,
114 base::BindOnce(&GotUsageAndQuotaDataCallback, std::move(callback)));
115 }
116
117 } // namespace
118
119 // Observer that listens on the IO thread for cache storage notifications and
120 // informs the StorageHandler on the UI thread for origins of interest.
121 // Created on the UI thread but predominantly used and deleted on the IO thread.
122 // Registered on creation as an observer in CacheStorageContextImpl,
123 // unregistered on destruction.
124 class StorageHandler::CacheStorageObserver : CacheStorageContextImpl::Observer {
125 public:
CacheStorageObserver(base::WeakPtr<StorageHandler> owner_storage_handler,CacheStorageContextImpl * cache_storage_context)126 CacheStorageObserver(base::WeakPtr<StorageHandler> owner_storage_handler,
127 CacheStorageContextImpl* cache_storage_context)
128 : owner_(owner_storage_handler), context_(cache_storage_context) {
129 DCHECK_CURRENTLY_ON(BrowserThread::UI);
130 context_->AddObserver(this);
131 }
132
~CacheStorageObserver()133 ~CacheStorageObserver() override {
134 DCHECK_CURRENTLY_ON(BrowserThread::UI);
135 context_->RemoveObserver(this);
136 }
137
TrackOrigin(const url::Origin & origin)138 void TrackOrigin(const url::Origin& origin) {
139 DCHECK_CURRENTLY_ON(BrowserThread::UI);
140 if (origins_.find(origin) != origins_.end())
141 return;
142 origins_.insert(origin);
143 }
144
UntrackOrigin(const url::Origin & origin)145 void UntrackOrigin(const url::Origin& origin) {
146 DCHECK_CURRENTLY_ON(BrowserThread::UI);
147 origins_.erase(origin);
148 }
149
OnCacheListChanged(const url::Origin & origin)150 void OnCacheListChanged(const url::Origin& origin) override {
151 DCHECK_CURRENTLY_ON(BrowserThread::UI);
152 auto found = origins_.find(origin);
153 if (found == origins_.end())
154 return;
155 owner_->NotifyCacheStorageListChanged(origin.Serialize());
156 }
157
OnCacheContentChanged(const url::Origin & origin,const std::string & cache_name)158 void OnCacheContentChanged(const url::Origin& origin,
159 const std::string& cache_name) override {
160 DCHECK_CURRENTLY_ON(BrowserThread::UI);
161 if (origins_.find(origin) == origins_.end())
162 return;
163 owner_->NotifyCacheStorageContentChanged(origin.Serialize(), cache_name);
164 }
165
166 private:
167 // Maintained on the IO thread to avoid thread contention.
168 base::flat_set<url::Origin> origins_;
169
170 base::WeakPtr<StorageHandler> owner_;
171 scoped_refptr<CacheStorageContextImpl> context_;
172
173 DISALLOW_COPY_AND_ASSIGN(CacheStorageObserver);
174 };
175
176 // Observer that listens on the IDB thread for IndexedDB notifications and
177 // informs the StorageHandler on the UI thread for origins of interest.
178 // Created on the UI thread but predominantly used and deleted on the IDB
179 // thread.
180 class StorageHandler::IndexedDBObserver
181 : public storage::mojom::IndexedDBObserver {
182 public:
IndexedDBObserver(base::WeakPtr<StorageHandler> owner_storage_handler)183 explicit IndexedDBObserver(
184 base::WeakPtr<StorageHandler> owner_storage_handler)
185 : owner_(owner_storage_handler), receiver_(this) {
186 DCHECK_CURRENTLY_ON(BrowserThread::UI);
187
188 ReconnectObserver();
189 }
190
~IndexedDBObserver()191 ~IndexedDBObserver() override { DCHECK_CURRENTLY_ON(BrowserThread::UI); }
192
TrackOrigin(const url::Origin & origin)193 void TrackOrigin(const url::Origin& origin) {
194 DCHECK_CURRENTLY_ON(BrowserThread::UI);
195 if (origins_.find(origin) != origins_.end())
196 return;
197 origins_.insert(origin);
198 }
199
UntrackOrigin(const url::Origin & origin)200 void UntrackOrigin(const url::Origin& origin) {
201 DCHECK_CURRENTLY_ON(BrowserThread::UI);
202 origins_.erase(origin);
203 }
204
OnIndexedDBListChanged(const url::Origin & origin)205 void OnIndexedDBListChanged(const url::Origin& origin) override {
206 DCHECK_CURRENTLY_ON(BrowserThread::UI);
207 if (!owner_)
208 return;
209 auto found = origins_.find(origin);
210 if (found == origins_.end())
211 return;
212 owner_->NotifyIndexedDBListChanged(origin.Serialize());
213 }
214
OnIndexedDBContentChanged(const url::Origin & origin,const base::string16 & database_name,const base::string16 & object_store_name)215 void OnIndexedDBContentChanged(
216 const url::Origin& origin,
217 const base::string16& database_name,
218 const base::string16& object_store_name) override {
219 DCHECK_CURRENTLY_ON(BrowserThread::UI);
220 if (!owner_)
221 return;
222 auto found = origins_.find(origin);
223 if (found == origins_.end())
224 return;
225 owner_->NotifyIndexedDBContentChanged(origin.Serialize(), database_name,
226 object_store_name);
227 }
228
229 private:
ReconnectObserver()230 void ReconnectObserver() {
231 DCHECK(!receiver_.is_bound());
232 if (!owner_)
233 return;
234
235 auto& control = owner_->storage_partition_->GetIndexedDBControl();
236 mojo::PendingRemote<storage::mojom::IndexedDBObserver> remote;
237 receiver_.Bind(remote.InitWithNewPipeAndPassReceiver());
238 receiver_.set_disconnect_handler(base::BindOnce(
239 [](IndexedDBObserver* observer) {
240 // If this observer disconnects because IndexedDB or the storage
241 // service goes away, reconnect again.
242 observer->ReconnectObserver();
243 },
244 this));
245 control.AddObserver(std::move(remote));
246 }
247
248 base::flat_set<url::Origin> origins_;
249 base::WeakPtr<StorageHandler> owner_;
250 mojo::Receiver<storage::mojom::IndexedDBObserver> receiver_;
251
252 DISALLOW_COPY_AND_ASSIGN(IndexedDBObserver);
253 };
254
StorageHandler()255 StorageHandler::StorageHandler()
256 : DevToolsDomainHandler(Storage::Metainfo::domainName),
257 storage_partition_(nullptr) {}
258
~StorageHandler()259 StorageHandler::~StorageHandler() {
260 DCHECK(!cache_storage_observer_);
261 DCHECK(!indexed_db_observer_);
262 }
263
Wire(UberDispatcher * dispatcher)264 void StorageHandler::Wire(UberDispatcher* dispatcher) {
265 frontend_ = std::make_unique<Storage::Frontend>(dispatcher->channel());
266 Storage::Dispatcher::wire(dispatcher, this);
267 }
268
SetRenderer(int process_host_id,RenderFrameHostImpl * frame_host)269 void StorageHandler::SetRenderer(int process_host_id,
270 RenderFrameHostImpl* frame_host) {
271 RenderProcessHost* process = RenderProcessHost::FromID(process_host_id);
272 storage_partition_ = process ? process->GetStoragePartition() : nullptr;
273 }
274
Disable()275 Response StorageHandler::Disable() {
276 cache_storage_observer_.reset();
277 indexed_db_observer_.reset();
278 quota_override_handle_.reset();
279 return Response::Success();
280 }
281
GetCookies(Maybe<std::string> browser_context_id,std::unique_ptr<GetCookiesCallback> callback)282 void StorageHandler::GetCookies(Maybe<std::string> browser_context_id,
283 std::unique_ptr<GetCookiesCallback> callback) {
284 StoragePartition* storage_partition = nullptr;
285 Response response = StorageHandler::FindStoragePartition(browser_context_id,
286 &storage_partition);
287 if (!response.IsSuccess()) {
288 callback->sendFailure(std::move(response));
289 return;
290 }
291
292 storage_partition->GetCookieManagerForBrowserProcess()->GetAllCookies(
293 base::BindOnce(
294 [](std::unique_ptr<GetCookiesCallback> callback,
295 const std::vector<net::CanonicalCookie>& cookies) {
296 callback->sendSuccess(NetworkHandler::BuildCookieArray(cookies));
297 },
298 std::move(callback)));
299 }
300
SetCookies(std::unique_ptr<protocol::Array<Network::CookieParam>> cookies,Maybe<std::string> browser_context_id,std::unique_ptr<SetCookiesCallback> callback)301 void StorageHandler::SetCookies(
302 std::unique_ptr<protocol::Array<Network::CookieParam>> cookies,
303 Maybe<std::string> browser_context_id,
304 std::unique_ptr<SetCookiesCallback> callback) {
305 StoragePartition* storage_partition = nullptr;
306 Response response = StorageHandler::FindStoragePartition(browser_context_id,
307 &storage_partition);
308 if (!response.IsSuccess()) {
309 callback->sendFailure(std::move(response));
310 return;
311 }
312
313 NetworkHandler::SetCookies(
314 storage_partition, std::move(cookies),
315 base::BindOnce(
316 [](std::unique_ptr<SetCookiesCallback> callback, bool success) {
317 if (success) {
318 callback->sendSuccess();
319 } else {
320 callback->sendFailure(
321 Response::InvalidParams("Invalid cookie fields"));
322 }
323 },
324 std::move(callback)));
325 }
326
ClearCookies(Maybe<std::string> browser_context_id,std::unique_ptr<ClearCookiesCallback> callback)327 void StorageHandler::ClearCookies(
328 Maybe<std::string> browser_context_id,
329 std::unique_ptr<ClearCookiesCallback> callback) {
330 StoragePartition* storage_partition = nullptr;
331 Response response = StorageHandler::FindStoragePartition(browser_context_id,
332 &storage_partition);
333 if (!response.IsSuccess()) {
334 callback->sendFailure(std::move(response));
335 return;
336 }
337
338 storage_partition->GetCookieManagerForBrowserProcess()->DeleteCookies(
339 network::mojom::CookieDeletionFilter::New(),
340 base::BindOnce([](std::unique_ptr<ClearCookiesCallback> callback,
341 uint32_t) { callback->sendSuccess(); },
342 std::move(callback)));
343 }
344
ClearDataForOrigin(const std::string & origin,const std::string & storage_types,std::unique_ptr<ClearDataForOriginCallback> callback)345 void StorageHandler::ClearDataForOrigin(
346 const std::string& origin,
347 const std::string& storage_types,
348 std::unique_ptr<ClearDataForOriginCallback> callback) {
349 if (!storage_partition_)
350 return callback->sendFailure(Response::InternalError());
351
352 std::vector<std::string> types = base::SplitString(
353 storage_types, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
354 std::unordered_set<std::string> set(types.begin(), types.end());
355 uint32_t remove_mask = 0;
356 if (set.count(Storage::StorageTypeEnum::Appcache))
357 remove_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE;
358 if (set.count(Storage::StorageTypeEnum::Cookies))
359 remove_mask |= StoragePartition::REMOVE_DATA_MASK_COOKIES;
360 if (set.count(Storage::StorageTypeEnum::File_systems))
361 remove_mask |= StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS;
362 if (set.count(Storage::StorageTypeEnum::Indexeddb))
363 remove_mask |= StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
364 if (set.count(Storage::StorageTypeEnum::Local_storage))
365 remove_mask |= StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE;
366 if (set.count(Storage::StorageTypeEnum::Shader_cache))
367 remove_mask |= StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE;
368 if (set.count(Storage::StorageTypeEnum::Websql))
369 remove_mask |= StoragePartition::REMOVE_DATA_MASK_WEBSQL;
370 if (set.count(Storage::StorageTypeEnum::Service_workers))
371 remove_mask |= StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS;
372 if (set.count(Storage::StorageTypeEnum::Cache_storage))
373 remove_mask |= StoragePartition::REMOVE_DATA_MASK_CACHE_STORAGE;
374 if (set.count(Storage::StorageTypeEnum::All))
375 remove_mask |= StoragePartition::REMOVE_DATA_MASK_ALL;
376
377 if (!remove_mask) {
378 return callback->sendFailure(
379 Response::InvalidParams("No valid storage type specified"));
380 }
381
382 storage_partition_->ClearData(
383 remove_mask, StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
384 GURL(origin), base::Time(), base::Time::Max(),
385 base::BindOnce(&ClearDataForOriginCallback::sendSuccess,
386 std::move(callback)));
387 }
388
GetUsageAndQuota(const String & origin,std::unique_ptr<GetUsageAndQuotaCallback> callback)389 void StorageHandler::GetUsageAndQuota(
390 const String& origin,
391 std::unique_ptr<GetUsageAndQuotaCallback> callback) {
392 if (!storage_partition_)
393 return callback->sendFailure(Response::InternalError());
394
395 GURL origin_url(origin);
396 if (!origin_url.is_valid()) {
397 return callback->sendFailure(
398 Response::ServerError(origin + " is not a valid URL"));
399 }
400
401 storage::QuotaManager* manager = storage_partition_->GetQuotaManager();
402 GetIOThreadTaskRunner({})->PostTask(
403 FROM_HERE,
404 base::BindOnce(&GetUsageAndQuotaOnIOThread, base::RetainedRef(manager),
405 url::Origin::Create(origin_url), std::move(callback)));
406 }
407
OverrideQuotaForOrigin(const String & origin_string,Maybe<double> quota_size,std::unique_ptr<OverrideQuotaForOriginCallback> callback)408 void StorageHandler::OverrideQuotaForOrigin(
409 const String& origin_string,
410 Maybe<double> quota_size,
411 std::unique_ptr<OverrideQuotaForOriginCallback> callback) {
412 if (!storage_partition_) {
413 callback->sendFailure(Response::InternalError());
414 return;
415 }
416
417 GURL url(origin_string);
418 url::Origin origin = url::Origin::Create(url);
419 if (!url.is_valid() || origin.opaque()) {
420 callback->sendFailure(
421 Response::InvalidParams(origin_string + " is not a valid URL"));
422 return;
423 }
424
425 if (!quota_override_handle_) {
426 scoped_refptr<storage::QuotaManagerProxy> manager_proxy =
427 storage_partition_->GetQuotaManager()->proxy();
428 quota_override_handle_ = manager_proxy->GetQuotaOverrideHandle();
429 }
430
431 quota_override_handle_->OverrideQuotaForOrigin(
432 origin,
433 quota_size.isJust() ? base::make_optional(quota_size.fromJust())
434 : base::nullopt,
435 base::BindOnce(&OverrideQuotaForOriginCallback::sendSuccess,
436 std::move(callback)));
437 }
438
TrackCacheStorageForOrigin(const std::string & origin)439 Response StorageHandler::TrackCacheStorageForOrigin(const std::string& origin) {
440 if (!storage_partition_)
441 return Response::InternalError();
442
443 GURL origin_url(origin);
444 if (!origin_url.is_valid())
445 return Response::InvalidParams(origin + " is not a valid URL");
446
447 GetCacheStorageObserver()->TrackOrigin(url::Origin::Create(origin_url));
448 return Response::Success();
449 }
450
UntrackCacheStorageForOrigin(const std::string & origin)451 Response StorageHandler::UntrackCacheStorageForOrigin(
452 const std::string& origin) {
453 if (!storage_partition_)
454 return Response::InternalError();
455
456 GURL origin_url(origin);
457 if (!origin_url.is_valid())
458 return Response::InvalidParams(origin + " is not a valid URL");
459
460 GetCacheStorageObserver()->UntrackOrigin(url::Origin::Create(origin_url));
461 return Response::Success();
462 }
463
TrackIndexedDBForOrigin(const std::string & origin)464 Response StorageHandler::TrackIndexedDBForOrigin(const std::string& origin) {
465 if (!storage_partition_)
466 return Response::InternalError();
467
468 GURL origin_url(origin);
469 if (!origin_url.is_valid())
470 return Response::InvalidParams(origin + " is not a valid URL");
471
472 GetIndexedDBObserver()->TrackOrigin(url::Origin::Create(origin_url));
473 return Response::Success();
474 }
475
UntrackIndexedDBForOrigin(const std::string & origin)476 Response StorageHandler::UntrackIndexedDBForOrigin(const std::string& origin) {
477 if (!storage_partition_)
478 return Response::InternalError();
479
480 GURL origin_url(origin);
481 if (!origin_url.is_valid())
482 return Response::InvalidParams(origin + " is not a valid URL");
483
484 GetIndexedDBObserver()->UntrackOrigin(url::Origin::Create(origin_url));
485 return Response::Success();
486 }
487
488 StorageHandler::CacheStorageObserver*
GetCacheStorageObserver()489 StorageHandler::GetCacheStorageObserver() {
490 DCHECK_CURRENTLY_ON(BrowserThread::UI);
491 if (!cache_storage_observer_) {
492 cache_storage_observer_ = std::make_unique<CacheStorageObserver>(
493 weak_ptr_factory_.GetWeakPtr(),
494 static_cast<CacheStorageContextImpl*>(
495 storage_partition_->GetCacheStorageContext()));
496 }
497 return cache_storage_observer_.get();
498 }
499
GetIndexedDBObserver()500 StorageHandler::IndexedDBObserver* StorageHandler::GetIndexedDBObserver() {
501 DCHECK_CURRENTLY_ON(BrowserThread::UI);
502 if (!indexed_db_observer_) {
503 indexed_db_observer_ =
504 std::make_unique<IndexedDBObserver>(weak_ptr_factory_.GetWeakPtr());
505 }
506 return indexed_db_observer_.get();
507 }
508
NotifyCacheStorageListChanged(const std::string & origin)509 void StorageHandler::NotifyCacheStorageListChanged(const std::string& origin) {
510 DCHECK_CURRENTLY_ON(BrowserThread::UI);
511 frontend_->CacheStorageListUpdated(origin);
512 }
513
NotifyCacheStorageContentChanged(const std::string & origin,const std::string & name)514 void StorageHandler::NotifyCacheStorageContentChanged(const std::string& origin,
515 const std::string& name) {
516 DCHECK_CURRENTLY_ON(BrowserThread::UI);
517 frontend_->CacheStorageContentUpdated(origin, name);
518 }
519
NotifyIndexedDBListChanged(const std::string & origin)520 void StorageHandler::NotifyIndexedDBListChanged(const std::string& origin) {
521 DCHECK_CURRENTLY_ON(BrowserThread::UI);
522 frontend_->IndexedDBListUpdated(origin);
523 }
524
NotifyIndexedDBContentChanged(const std::string & origin,const base::string16 & database_name,const base::string16 & object_store_name)525 void StorageHandler::NotifyIndexedDBContentChanged(
526 const std::string& origin,
527 const base::string16& database_name,
528 const base::string16& object_store_name) {
529 DCHECK_CURRENTLY_ON(BrowserThread::UI);
530 frontend_->IndexedDBContentUpdated(origin, base::UTF16ToUTF8(database_name),
531 base::UTF16ToUTF8(object_store_name));
532 }
533
FindStoragePartition(const Maybe<std::string> & browser_context_id,StoragePartition ** storage_partition)534 Response StorageHandler::FindStoragePartition(
535 const Maybe<std::string>& browser_context_id,
536 StoragePartition** storage_partition) {
537 BrowserContext* browser_context = nullptr;
538 Response response =
539 BrowserHandler::FindBrowserContext(browser_context_id, &browser_context);
540 if (!response.IsSuccess())
541 return response;
542 *storage_partition =
543 BrowserContext::GetDefaultStoragePartition(browser_context);
544 if (!*storage_partition)
545 return Response::InternalError();
546 return Response::Success();
547 }
548
549 } // namespace protocol
550 } // namespace content
551