1 // Copyright (c) 2020 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/indexed_db/indexed_db_control_wrapper.h"
6 
7 #include "base/task/post_task.h"
8 #include "content/public/browser/browser_task_traits.h"
9 #include "content/public/browser/browser_thread.h"
10 
11 namespace content {
12 
13 // Observer for the SpecialStoragePolicy on the IO thread.
14 class IndexedDBControlWrapper::StoragePolicyObserver
15     : public storage::SpecialStoragePolicy::Observer {
16  public:
StoragePolicyObserver(scoped_refptr<base::SequencedTaskRunner> reply_task_runner,scoped_refptr<storage::SpecialStoragePolicy> storage_policy,base::WeakPtr<IndexedDBControlWrapper> control_wrapper)17   explicit StoragePolicyObserver(
18       scoped_refptr<base::SequencedTaskRunner> reply_task_runner,
19       scoped_refptr<storage::SpecialStoragePolicy> storage_policy,
20       base::WeakPtr<IndexedDBControlWrapper> control_wrapper)
21       : reply_task_runner_(std::move(reply_task_runner)),
22         storage_policy_(std::move(storage_policy)),
23         control_wrapper_(std::move(control_wrapper)) {
24     storage_policy_->AddObserver(this);
25   }
26 
~StoragePolicyObserver()27   ~StoragePolicyObserver() override { storage_policy_->RemoveObserver(this); }
28 
29   // storage::SpecialStoragePolicy::Observer implementation:
OnPolicyChanged()30   void OnPolicyChanged() override {
31     reply_task_runner_->PostTask(
32         FROM_HERE,
33         base::BindOnce(&IndexedDBControlWrapper::OnSpecialStoragePolicyChanged,
34                        control_wrapper_));
35   }
36 
37  private:
38   scoped_refptr<base::SequencedTaskRunner> reply_task_runner_;
39   scoped_refptr<storage::SpecialStoragePolicy> storage_policy_;
40 
41   // control_wrapper_ is bound to the reply_task_runner sequence,
42   // so should not be checked other than on that sequence.
43   base::WeakPtr<IndexedDBControlWrapper> control_wrapper_;
44 };
45 
IndexedDBControlWrapper(const base::FilePath & data_path,scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,base::Clock * clock,mojo::PendingRemote<storage::mojom::BlobStorageContext> blob_storage_context,mojo::PendingRemote<storage::mojom::NativeFileSystemContext> native_file_system_context,scoped_refptr<base::SequencedTaskRunner> io_task_runner,scoped_refptr<base::SequencedTaskRunner> custom_task_runner)46 IndexedDBControlWrapper::IndexedDBControlWrapper(
47     const base::FilePath& data_path,
48     scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
49     scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
50     base::Clock* clock,
51     mojo::PendingRemote<storage::mojom::BlobStorageContext>
52         blob_storage_context,
53     mojo::PendingRemote<storage::mojom::NativeFileSystemContext>
54         native_file_system_context,
55     scoped_refptr<base::SequencedTaskRunner> io_task_runner,
56     scoped_refptr<base::SequencedTaskRunner> custom_task_runner)
57     : special_storage_policy_(std::move(special_storage_policy)) {
58   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
59   context_ = base::MakeRefCounted<IndexedDBContextImpl>(
60       data_path, std::move(quota_manager_proxy), clock,
61       std::move(blob_storage_context), std::move(native_file_system_context),
62       io_task_runner, std::move(custom_task_runner));
63 
64   if (special_storage_policy_) {
65     storage_policy_observer_ = base::SequenceBound<StoragePolicyObserver>(
66         io_task_runner, base::SequencedTaskRunnerHandle::Get(),
67         special_storage_policy_, weak_factory_.GetWeakPtr());
68   }
69 }
70 
~IndexedDBControlWrapper()71 IndexedDBControlWrapper::~IndexedDBControlWrapper() {
72   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
73 }
74 
BindIndexedDB(const url::Origin & origin,mojo::PendingReceiver<blink::mojom::IDBFactory> receiver)75 void IndexedDBControlWrapper::BindIndexedDB(
76     const url::Origin& origin,
77     mojo::PendingReceiver<blink::mojom::IDBFactory> receiver) {
78   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
79   BindRemoteIfNeeded();
80   TrackOriginPolicyState(origin);
81   indexed_db_control_->BindIndexedDB(origin, std::move(receiver));
82 }
83 
GetUsage(GetUsageCallback usage_callback)84 void IndexedDBControlWrapper::GetUsage(GetUsageCallback usage_callback) {
85   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
86   BindRemoteIfNeeded();
87   indexed_db_control_->GetUsage(std::move(usage_callback));
88 }
89 
DeleteForOrigin(const url::Origin & origin,DeleteForOriginCallback callback)90 void IndexedDBControlWrapper::DeleteForOrigin(
91     const url::Origin& origin,
92     DeleteForOriginCallback callback) {
93   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
94   BindRemoteIfNeeded();
95   indexed_db_control_->DeleteForOrigin(origin, std::move(callback));
96 }
97 
ForceClose(const url::Origin & origin,storage::mojom::ForceCloseReason reason,base::OnceClosure callback)98 void IndexedDBControlWrapper::ForceClose(
99     const url::Origin& origin,
100     storage::mojom::ForceCloseReason reason,
101     base::OnceClosure callback) {
102   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
103   BindRemoteIfNeeded();
104   indexed_db_control_->ForceClose(origin, reason, std::move(callback));
105 }
106 
GetConnectionCount(const url::Origin & origin,GetConnectionCountCallback callback)107 void IndexedDBControlWrapper::GetConnectionCount(
108     const url::Origin& origin,
109     GetConnectionCountCallback callback) {
110   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
111   BindRemoteIfNeeded();
112   indexed_db_control_->GetConnectionCount(origin, std::move(callback));
113 }
114 
DownloadOriginData(const url::Origin & origin,DownloadOriginDataCallback callback)115 void IndexedDBControlWrapper::DownloadOriginData(
116     const url::Origin& origin,
117     DownloadOriginDataCallback callback) {
118   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
119   BindRemoteIfNeeded();
120   indexed_db_control_->DownloadOriginData(origin, std::move(callback));
121 }
122 
GetAllOriginsDetails(GetAllOriginsDetailsCallback callback)123 void IndexedDBControlWrapper::GetAllOriginsDetails(
124     GetAllOriginsDetailsCallback callback) {
125   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
126   BindRemoteIfNeeded();
127   indexed_db_control_->GetAllOriginsDetails(std::move(callback));
128 }
129 
SetForceKeepSessionState()130 void IndexedDBControlWrapper::SetForceKeepSessionState() {
131   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
132   BindRemoteIfNeeded();
133   indexed_db_control_->SetForceKeepSessionState();
134 }
135 
ApplyPolicyUpdates(std::vector<storage::mojom::IndexedDBStoragePolicyUpdatePtr> policy_updates)136 void IndexedDBControlWrapper::ApplyPolicyUpdates(
137     std::vector<storage::mojom::IndexedDBStoragePolicyUpdatePtr>
138         policy_updates) {
139   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
140   BindRemoteIfNeeded();
141   indexed_db_control_->ApplyPolicyUpdates(std::move(policy_updates));
142 }
143 
BindTestInterface(mojo::PendingReceiver<storage::mojom::IndexedDBControlTest> receiver)144 void IndexedDBControlWrapper::BindTestInterface(
145     mojo::PendingReceiver<storage::mojom::IndexedDBControlTest> receiver) {
146   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
147   BindRemoteIfNeeded();
148   indexed_db_control_->BindTestInterface(std::move(receiver));
149 }
150 
AddObserver(mojo::PendingRemote<storage::mojom::IndexedDBObserver> observer)151 void IndexedDBControlWrapper::AddObserver(
152     mojo::PendingRemote<storage::mojom::IndexedDBObserver> observer) {
153   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
154   BindRemoteIfNeeded();
155   indexed_db_control_->AddObserver(std::move(observer));
156 }
157 
OnSpecialStoragePolicyChanged()158 void IndexedDBControlWrapper::OnSpecialStoragePolicyChanged() {
159   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
160   BindRemoteIfNeeded();
161 
162   std::vector<storage::mojom::IndexedDBStoragePolicyUpdatePtr> policy_updates;
163   for (auto& entry : origin_state_) {
164     const GURL& origin = entry.first;
165     OriginState& state = entry.second;
166     state.should_purge_on_shutdown = ShouldPurgeOnShutdown(origin);
167 
168     if (state.should_purge_on_shutdown != state.will_purge_on_shutdown) {
169       state.will_purge_on_shutdown = state.should_purge_on_shutdown;
170       policy_updates.push_back(
171           storage::mojom::IndexedDBStoragePolicyUpdate::New(
172               url::Origin::Create(origin), state.should_purge_on_shutdown));
173     }
174   }
175   if (!policy_updates.empty())
176     ApplyPolicyUpdates(std::move(policy_updates));
177 }
178 
TrackOriginPolicyState(const url::Origin & origin)179 void IndexedDBControlWrapper::TrackOriginPolicyState(
180     const url::Origin& origin) {
181   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
182   const GURL origin_url = GURL(origin.Serialize());
183   auto it = origin_state_.find(origin_url);
184   if (it == origin_state_.end())
185     origin_state_[origin_url] = {};
186   OnSpecialStoragePolicyChanged();
187 }
188 
ShouldPurgeOnShutdown(const GURL & origin)189 bool IndexedDBControlWrapper::ShouldPurgeOnShutdown(const GURL& origin) {
190   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
191   if (!special_storage_policy_)
192     return false;
193   if (!special_storage_policy_->IsStorageSessionOnly(origin))
194     return false;
195   if (special_storage_policy_->IsStorageProtected(origin))
196     return false;
197   return true;
198 }
199 
BindRemoteIfNeeded()200 void IndexedDBControlWrapper::BindRemoteIfNeeded() {
201   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
202   DCHECK(
203       !(indexed_db_control_.is_bound() && !indexed_db_control_.is_connected()))
204       << "Rebinding is not supported yet.";
205 
206   if (indexed_db_control_.is_bound())
207     return;
208   IndexedDBContextImpl* idb_context = GetIndexedDBContextInternal();
209   idb_context->IDBTaskRunner()->PostTask(
210       FROM_HERE,
211       base::BindOnce(&IndexedDBContextImpl::Bind,
212                      base::WrapRefCounted(idb_context),
213                      indexed_db_control_.BindNewPipeAndPassReceiver()));
214 }
215 
216 }  // namespace content
217