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