Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: content/browser/dom_storage/local_storage_context_mojo.cc

Issue 2861473002: Clear up session only storage on localstorage shutdown (Closed)
Patch Set: test and nicer Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/dom_storage/local_storage_context_mojo.h" 5 #include "content/browser/dom_storage/local_storage_context_mojo.h"
6 6
7 #include "base/memory/ptr_util.h" 7 #include "base/memory/ptr_util.h"
8 #include "base/metrics/histogram_macros.h" 8 #include "base/metrics/histogram_macros.h"
9 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_number_conversions.h"
10 #include "components/leveldb/public/cpp/util.h" 10 #include "components/leveldb/public/cpp/util.h"
11 #include "components/leveldb/public/interfaces/leveldb.mojom.h" 11 #include "components/leveldb/public/interfaces/leveldb.mojom.h"
12 #include "content/browser/dom_storage/dom_storage_area.h" 12 #include "content/browser/dom_storage/dom_storage_area.h"
13 #include "content/browser/dom_storage/dom_storage_database.h" 13 #include "content/browser/dom_storage/dom_storage_database.h"
14 #include "content/browser/dom_storage/dom_storage_task_runner.h" 14 #include "content/browser/dom_storage/dom_storage_task_runner.h"
15 #include "content/browser/dom_storage/local_storage_database.pb.h" 15 #include "content/browser/dom_storage/local_storage_database.pb.h"
16 #include "content/browser/leveldb_wrapper_impl.h" 16 #include "content/browser/leveldb_wrapper_impl.h"
17 #include "content/common/dom_storage/dom_storage_types.h" 17 #include "content/common/dom_storage/dom_storage_types.h"
18 #include "content/public/browser/local_storage_usage_info.h" 18 #include "content/public/browser/local_storage_usage_info.h"
19 #include "services/file/public/interfaces/constants.mojom.h" 19 #include "services/file/public/interfaces/constants.mojom.h"
20 #include "services/service_manager/public/cpp/connector.h" 20 #include "services/service_manager/public/cpp/connector.h"
21 #include "sql/connection.h" 21 #include "sql/connection.h"
22 #include "storage/browser/quota/special_storage_policy.h"
22 #include "third_party/leveldatabase/env_chromium.h" 23 #include "third_party/leveldatabase/env_chromium.h"
23 24
24 namespace content { 25 namespace content {
25 26
26 // LevelDB database schema 27 // LevelDB database schema
27 // ======================= 28 // =======================
28 // 29 //
29 // Version 1 (in sorted order): 30 // Version 1 (in sorted order):
30 // key: "VERSION" 31 // key: "VERSION"
31 // value: "1" 32 // value: "1"
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 // called and need access to the LevelDBWrapperImpl instance. The unique_ptr 213 // called and need access to the LevelDBWrapperImpl instance. The unique_ptr
213 // could already be null, but this field should still be valid. 214 // could already be null, but this field should still be valid.
214 LevelDBWrapperImpl* level_db_wrapper_ptr_; 215 LevelDBWrapperImpl* level_db_wrapper_ptr_;
215 bool deleted_old_data_ = false; 216 bool deleted_old_data_ = false;
216 }; 217 };
217 218
218 LocalStorageContextMojo::LocalStorageContextMojo( 219 LocalStorageContextMojo::LocalStorageContextMojo(
219 service_manager::Connector* connector, 220 service_manager::Connector* connector,
220 scoped_refptr<DOMStorageTaskRunner> task_runner, 221 scoped_refptr<DOMStorageTaskRunner> task_runner,
221 const base::FilePath& old_localstorage_path, 222 const base::FilePath& old_localstorage_path,
222 const base::FilePath& subdirectory) 223 const base::FilePath& subdirectory,
223 : connector_(connector), 224 storage::SpecialStoragePolicy* special_storage_policy)
225 : connector_(connector ? connector->Clone() : nullptr),
224 subdirectory_(subdirectory), 226 subdirectory_(subdirectory),
227 special_storage_policy_(special_storage_policy),
225 task_runner_(std::move(task_runner)), 228 task_runner_(std::move(task_runner)),
226 old_localstorage_path_(old_localstorage_path), 229 old_localstorage_path_(old_localstorage_path),
227 weak_ptr_factory_(this) {} 230 weak_ptr_factory_(this) {}
228 231
229 LocalStorageContextMojo::~LocalStorageContextMojo() {}
230
231 void LocalStorageContextMojo::OpenLocalStorage( 232 void LocalStorageContextMojo::OpenLocalStorage(
232 const url::Origin& origin, 233 const url::Origin& origin,
233 mojom::LevelDBWrapperRequest request) { 234 mojom::LevelDBWrapperRequest request) {
234 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::BindLocalStorage, 235 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::BindLocalStorage,
235 weak_ptr_factory_.GetWeakPtr(), origin, 236 weak_ptr_factory_.GetWeakPtr(), origin,
236 std::move(request))); 237 std::move(request)));
237 } 238 }
238 239
239 void LocalStorageContextMojo::GetStorageUsage( 240 void LocalStorageContextMojo::GetStorageUsage(
240 GetStorageUsageCallback callback) { 241 GetStorageUsageCallback callback) {
241 RunWhenConnected( 242 RunWhenConnected(
242 base::BindOnce(&LocalStorageContextMojo::RetrieveStorageUsage, 243 base::BindOnce(&LocalStorageContextMojo::RetrieveStorageUsage,
243 weak_ptr_factory_.GetWeakPtr(), std::move(callback))); 244 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
244 } 245 }
245 246
246 void LocalStorageContextMojo::DeleteStorage(const url::Origin& origin) { 247 void LocalStorageContextMojo::DeleteStorage(const url::Origin& origin) {
247 if (connection_state_ != CONNECTION_FINISHED) { 248 if (connection_state_ != CONNECTION_FINISHED) {
248 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::DeleteStorage, 249 RunWhenConnected(
249 weak_ptr_factory_.GetWeakPtr(), origin)); 250 base::BindOnce(&LocalStorageContextMojo::DeleteStorage, this, origin));
250 return; 251 return;
251 } 252 }
252 253
253 LevelDBWrapperImpl* wrapper = GetOrCreateDBWrapper(origin); 254 LevelDBWrapperImpl* wrapper = GetOrCreateDBWrapper(origin);
254 // Renderer process expects |source| to always be two newline separated 255 // Renderer process expects |source| to always be two newline separated
255 // strings. 256 // strings.
256 wrapper->DeleteAll("\n", base::Bind(&NoOpSuccess)); 257 wrapper->DeleteAll("\n", base::Bind(&NoOpSuccess));
257 wrapper->ScheduleImmediateCommit(); 258 wrapper->ScheduleImmediateCommit();
258 } 259 }
259 260
260 void LocalStorageContextMojo::DeleteStorageForPhysicalOrigin( 261 void LocalStorageContextMojo::DeleteStorageForPhysicalOrigin(
261 const url::Origin& origin) { 262 const url::Origin& origin) {
262 GetStorageUsage(base::BindOnce( 263 GetStorageUsage(base::BindOnce(
263 &LocalStorageContextMojo::OnGotStorageUsageForDeletePhysicalOrigin, 264 &LocalStorageContextMojo::OnGotStorageUsageForDeletePhysicalOrigin, this,
264 weak_ptr_factory_.GetWeakPtr(), origin)); 265 origin));
265 } 266 }
266 267
267 void LocalStorageContextMojo::Flush() { 268 void LocalStorageContextMojo::Flush() {
268 if (connection_state_ != CONNECTION_FINISHED) { 269 if (connection_state_ != CONNECTION_FINISHED) {
269 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::Flush, 270 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::Flush,
270 weak_ptr_factory_.GetWeakPtr())); 271 weak_ptr_factory_.GetWeakPtr()));
271 return; 272 return;
272 } 273 }
273 for (const auto& it : level_db_wrappers_) 274 for (const auto& it : level_db_wrappers_)
274 it.second->level_db_wrapper()->ScheduleImmediateCommit(); 275 it.second->level_db_wrapper()->ScheduleImmediateCommit();
275 } 276 }
276 277
278 void LocalStorageContextMojo::Shutdown() {
279 DCHECK(!is_shutdown_);
280 DCHECK_NE(connection_state_, CONNECTION_SHUTDOWN);
281
282 // Nothing to do if no connection to the database was ever made.
283 if (connection_state_ == NO_CONNECTION) {
284 connection_state_ = CONNECTION_SHUTDOWN;
285 is_shutdown_ = true;
286 return;
287 }
288
289 if (connection_state_ != CONNECTION_FINISHED) {
michaeln 2017/05/03 21:01:29 Similar to the NO_CONNECTION case, maybe we don't
Marijn Kruisselbrink 2017/05/04 23:03:46 Yeah, agreed that it makes sense to just immediate
290 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::Shutdown, this));
291 return;
292 }
293
294 connection_state_ = CONNECTION_SHUTDOWN;
295
296 // Flush any uncommitted data.
297 for (const auto& it : level_db_wrappers_)
298 it.second->level_db_wrapper()->ScheduleImmediateCommit();
299
300 // Respect the content policy settings about what to
301 // keep and what to discard.
302 if (force_keep_session_state_) {
303 OnShutdownCommitComplete(leveldb::mojom::DatabaseError::OK);
304 return; // Keep everything.
305 }
306
307 bool has_session_only_origins =
308 special_storage_policy_.get() &&
309 special_storage_policy_->HasSessionOnlyOrigins();
310
311 if (has_session_only_origins) {
312 RetrieveStorageUsage(base::BindOnce(
313 &LocalStorageContextMojo::OnGotStorageUsageForShutdown, this));
314 } else {
315 OnShutdownCommitComplete(leveldb::mojom::DatabaseError::OK);
316 }
317 }
318
277 void LocalStorageContextMojo::PurgeMemory() { 319 void LocalStorageContextMojo::PurgeMemory() {
278 for (const auto& it : level_db_wrappers_) 320 for (const auto& it : level_db_wrappers_)
279 it.second->level_db_wrapper()->PurgeMemory(); 321 it.second->level_db_wrapper()->PurgeMemory();
280 } 322 }
281 323
282 leveldb::mojom::LevelDBDatabaseAssociatedRequest 324 leveldb::mojom::LevelDBDatabaseAssociatedRequest
283 LocalStorageContextMojo::DatabaseRequestForTesting() { 325 LocalStorageContextMojo::DatabaseRequestForTesting() {
284 DCHECK_EQ(connection_state_, NO_CONNECTION); 326 DCHECK_EQ(connection_state_, NO_CONNECTION);
285 connection_state_ = CONNECTION_IN_PROGRESS; 327 connection_state_ = CONNECTION_IN_PROGRESS;
286 leveldb::mojom::LevelDBDatabaseAssociatedRequest request = 328 leveldb::mojom::LevelDBDatabaseAssociatedRequest request =
287 MakeIsolatedRequest(&database_); 329 MakeIsolatedRequest(&database_);
288 OnDatabaseOpened(true, leveldb::mojom::DatabaseError::OK); 330 OnDatabaseOpened(true, leveldb::mojom::DatabaseError::OK);
289 return request; 331 return request;
290 } 332 }
291 333
292 // static 334 // static
293 std::vector<uint8_t> LocalStorageContextMojo::MigrateString( 335 std::vector<uint8_t> LocalStorageContextMojo::MigrateString(
294 const base::string16& input) { 336 const base::string16& input) {
295 static const uint8_t kUTF16Format = 0; 337 static const uint8_t kUTF16Format = 0;
296 338
297 const uint8_t* data = reinterpret_cast<const uint8_t*>(input.data()); 339 const uint8_t* data = reinterpret_cast<const uint8_t*>(input.data());
298 std::vector<uint8_t> result; 340 std::vector<uint8_t> result;
299 result.reserve(input.size() * sizeof(base::char16) + 1); 341 result.reserve(input.size() * sizeof(base::char16) + 1);
300 result.push_back(kUTF16Format); 342 result.push_back(kUTF16Format);
301 result.insert(result.end(), data, data + input.size() * sizeof(base::char16)); 343 result.insert(result.end(), data, data + input.size() * sizeof(base::char16));
302 return result; 344 return result;
303 } 345 }
304 346
347 LocalStorageContextMojo::~LocalStorageContextMojo() {
348 DCHECK(is_shutdown_);
349 DCHECK_EQ(connection_state_, CONNECTION_SHUTDOWN);
350 }
351
305 void LocalStorageContextMojo::RunWhenConnected(base::OnceClosure callback) { 352 void LocalStorageContextMojo::RunWhenConnected(base::OnceClosure callback) {
353 DCHECK_NE(connection_state_, CONNECTION_SHUTDOWN);
354
306 // If we don't have a filesystem_connection_, we'll need to establish one. 355 // If we don't have a filesystem_connection_, we'll need to establish one.
307 if (connection_state_ == NO_CONNECTION) { 356 if (connection_state_ == NO_CONNECTION) {
308 connection_state_ = CONNECTION_IN_PROGRESS; 357 connection_state_ = CONNECTION_IN_PROGRESS;
309 InitiateConnection(); 358 InitiateConnection();
310 } 359 }
311 360
312 if (connection_state_ == CONNECTION_IN_PROGRESS) { 361 if (connection_state_ == CONNECTION_IN_PROGRESS) {
313 // Queue this OpenLocalStorage call for when we have a level db pointer. 362 // Queue this OpenLocalStorage call for when we have a level db pointer.
314 on_database_opened_callbacks_.push_back(std::move(callback)); 363 on_database_opened_callbacks_.push_back(std::move(callback));
315 return; 364 return;
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 std::vector<LocalStorageUsageInfo> usage) { 626 std::vector<LocalStorageUsageInfo> usage) {
578 for (const auto& info : usage) { 627 for (const auto& info : usage) {
579 url::Origin origin_candidate(info.origin); 628 url::Origin origin_candidate(info.origin);
580 if (!origin_candidate.IsSameOriginWith(origin) && 629 if (!origin_candidate.IsSameOriginWith(origin) &&
581 origin_candidate.IsSamePhysicalOriginWith(origin)) 630 origin_candidate.IsSamePhysicalOriginWith(origin))
582 DeleteStorage(origin_candidate); 631 DeleteStorage(origin_candidate);
583 } 632 }
584 DeleteStorage(origin); 633 DeleteStorage(origin);
585 } 634 }
586 635
636 void LocalStorageContextMojo::OnGotStorageUsageForShutdown(
637 std::vector<LocalStorageUsageInfo> usage) {
638 std::vector<leveldb::mojom::BatchedOperationPtr> operations;
639 for (const auto& info : usage) {
640 if (special_storage_policy_->IsStorageProtected(info.origin))
641 continue;
642 if (!special_storage_policy_->IsStorageSessionOnly(info.origin))
643 continue;
644
645 url::Origin origin(info.origin);
michaeln 2017/05/03 21:01:29 i see you've copied the behavior for the sqlite im
Marijn Kruisselbrink 2017/05/04 23:03:46 Not sure.. but I imagine properly accounting for s
646 leveldb::mojom::BatchedOperationPtr item =
647 leveldb::mojom::BatchedOperation::New();
648 item->type = leveldb::mojom::BatchOperationType::DELETE_PREFIXED_KEY;
649 item->key = leveldb::StdStringToUint8Vector(
650 kDataPrefix + origin.Serialize() + kOriginSeparator);
651 operations.push_back(std::move(item));
652
653 item = leveldb::mojom::BatchedOperation::New();
654 item->type = leveldb::mojom::BatchOperationType::DELETE_KEY;
655 item->key = CreateMetaDataKey(origin);
656 operations.push_back(std::move(item));
657 }
658
659 if (!operations.empty()) {
660 database_->Write(
661 std::move(operations),
662 base::Bind(&LocalStorageContextMojo::OnShutdownCommitComplete, this));
663 } else {
664 OnShutdownCommitComplete(leveldb::mojom::DatabaseError::OK);
665 }
666 }
667
668 void LocalStorageContextMojo::OnShutdownCommitComplete(
669 leveldb::mojom::DatabaseError error) {
670 is_shutdown_ = true;
671 file_system_.reset();
672 directory_.reset();
673 leveldb_service_.reset();
674 level_db_wrappers_.clear();
675 database_.reset();
676 connector_.reset();
677 }
678
587 } // namespace content 679 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698