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

Side by Side Diff: chrome/browser/net/sqlite_persistent_cookie_store.cc

Issue 10918220: Delete the cookie DB when an unrecoverable error is detected. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: RefCounted require protected destructor. Created 8 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/net/sqlite_persistent_cookie_store.h" 5 #include "chrome/browser/net/sqlite_persistent_cookie_store.h"
6 6
7 #include <list> 7 #include <list>
8 #include <map> 8 #include <map>
9 #include <set> 9 #include <set>
10 #include <utility> 10 #include <utility>
(...skipping 14 matching lines...) Expand all
25 #include "base/time.h" 25 #include "base/time.h"
26 #include "chrome/browser/diagnostics/sqlite_diagnostics.h" 26 #include "chrome/browser/diagnostics/sqlite_diagnostics.h"
27 #include "chrome/browser/net/clear_on_exit_policy.h" 27 #include "chrome/browser/net/clear_on_exit_policy.h"
28 #include "content/public/browser/browser_thread.h" 28 #include "content/public/browser/browser_thread.h"
29 #include "googleurl/src/gurl.h" 29 #include "googleurl/src/gurl.h"
30 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 30 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
31 #include "net/cookies/canonical_cookie.h" 31 #include "net/cookies/canonical_cookie.h"
32 #include "sql/meta_table.h" 32 #include "sql/meta_table.h"
33 #include "sql/statement.h" 33 #include "sql/statement.h"
34 #include "sql/transaction.h" 34 #include "sql/transaction.h"
35 #include "third_party/sqlite/sqlite3.h"
35 36
36 using base::Time; 37 using base::Time;
37 using content::BrowserThread; 38 using content::BrowserThread;
38 39
39 // This class is designed to be shared between any calling threads and the 40 // This class is designed to be shared between any calling threads and the
40 // database thread. It batches operations and commits them on a timer. 41 // database thread. It batches operations and commits them on a timer.
41 // 42 //
42 // SQLitePersistentCookieStore::Load is called to load all cookies. It 43 // SQLitePersistentCookieStore::Load is called to load all cookies. It
43 // delegates to Backend::Load, which posts a Backend::LoadAndNotifyOnDBThread 44 // delegates to Backend::Load, which posts a Backend::LoadAndNotifyOnDBThread
44 // task to the DB thread. This task calls Backend::ChainLoadCookies(), which 45 // task to the DB thread. This task calls Backend::ChainLoadCookies(), which
(...skipping 22 matching lines...) Expand all
67 : path_(path), 68 : path_(path),
68 db_(NULL), 69 db_(NULL),
69 num_pending_(0), 70 num_pending_(0),
70 force_keep_session_state_(false), 71 force_keep_session_state_(false),
71 initialized_(false), 72 initialized_(false),
72 restore_old_session_cookies_(restore_old_session_cookies), 73 restore_old_session_cookies_(restore_old_session_cookies),
73 clear_on_exit_policy_(clear_on_exit_policy), 74 clear_on_exit_policy_(clear_on_exit_policy),
74 num_cookies_read_(0), 75 num_cookies_read_(0),
75 num_priority_waiting_(0), 76 num_priority_waiting_(0),
76 total_priority_requests_(0) { 77 total_priority_requests_(0) {
78 error_delegate_ =
79 new KillDatabaseErrorDelegate(this, GetErrorHandlerForCookieDb());
77 } 80 }
78 81
79 // Creates or loads the SQLite database. 82 // Creates or loads the SQLite database.
80 void Load(const LoadedCallback& loaded_callback); 83 void Load(const LoadedCallback& loaded_callback);
81 84
82 // Loads cookies for the domain key (eTLD+1). 85 // Loads cookies for the domain key (eTLD+1).
83 void LoadCookiesForKey(const std::string& domain, 86 void LoadCookiesForKey(const std::string& domain,
84 const LoadedCallback& loaded_callback); 87 const LoadedCallback& loaded_callback);
85 88
86 // Batch a cookie addition. 89 // Batch a cookie addition.
(...skipping 10 matching lines...) Expand all
97 100
98 // Commit any pending operations and close the database. This must be called 101 // Commit any pending operations and close the database. This must be called
99 // before the object is destructed. 102 // before the object is destructed.
100 void Close(); 103 void Close();
101 104
102 void SetForceKeepSessionState(); 105 void SetForceKeepSessionState();
103 106
104 private: 107 private:
105 friend class base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend>; 108 friend class base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend>;
106 109
110 class KillDatabaseErrorDelegate : public sql::ErrorDelegate {
111 public:
112 KillDatabaseErrorDelegate(Backend* backend,
113 sql::ErrorDelegate* wrapped_delegate);
114 // ErrorDelegate implementation.
115 virtual int OnError(int error,
116 sql::Connection* connection,
117 sql::Statement* stmt) OVERRIDE;
118
119 void reset_backend() {
120 backend_ = NULL;
121 }
122
123 protected:
124 virtual ~KillDatabaseErrorDelegate() {}
125
126 private:
127
128 // Do not increment the count on Backend, as that would create a circular
129 // reference (Backend -> Connection -> ErrorDelegate -> Backend). Instead,
130 // Backend will call reset_backend() when it is going away.
131 Backend* backend_;
132 scoped_refptr<sql::ErrorDelegate> wrapped_delegate_;
133
134 DISALLOW_COPY_AND_ASSIGN(KillDatabaseErrorDelegate);
135 };
136
107 // You should call Close() before destructing this object. 137 // You should call Close() before destructing this object.
108 ~Backend() { 138 ~Backend() {
139 if (error_delegate_.get()) {
140 error_delegate_->reset_backend();
141 error_delegate_ = NULL;
142 }
109 DCHECK(!db_.get()) << "Close should have already been called."; 143 DCHECK(!db_.get()) << "Close should have already been called.";
110 DCHECK(num_pending_ == 0 && pending_.empty()); 144 DCHECK(num_pending_ == 0 && pending_.empty());
111 } 145 }
112 146
113 // Database upgrade statements. 147 // Database upgrade statements.
114 bool EnsureDatabaseVersion(); 148 bool EnsureDatabaseVersion();
115 149
116 class PendingOperation { 150 class PendingOperation {
117 public: 151 public:
118 typedef enum { 152 typedef enum {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 const net::CanonicalCookie& cc); 216 const net::CanonicalCookie& cc);
183 // Commit our pending operations to the database. 217 // Commit our pending operations to the database.
184 void Commit(); 218 void Commit();
185 // Close() executed on the background thread. 219 // Close() executed on the background thread.
186 void InternalBackgroundClose(); 220 void InternalBackgroundClose();
187 221
188 void DeleteSessionCookiesOnStartup(); 222 void DeleteSessionCookiesOnStartup();
189 223
190 void DeleteSessionCookiesOnShutdown(); 224 void DeleteSessionCookiesOnShutdown();
191 225
226 void KillDatabase();
227
192 FilePath path_; 228 FilePath path_;
193 scoped_ptr<sql::Connection> db_; 229 scoped_ptr<sql::Connection> db_;
230 scoped_refptr<KillDatabaseErrorDelegate> error_delegate_;
194 sql::MetaTable meta_table_; 231 sql::MetaTable meta_table_;
195 232
196 typedef std::list<PendingOperation*> PendingOperationsList; 233 typedef std::list<PendingOperation*> PendingOperationsList;
197 PendingOperationsList pending_; 234 PendingOperationsList pending_;
198 PendingOperationsList::size_type num_pending_; 235 PendingOperationsList::size_type num_pending_;
199 // True if the persistent store should skip delete on exit rules. 236 // True if the persistent store should skip delete on exit rules.
200 bool force_keep_session_state_; 237 bool force_keep_session_state_;
201 // Guard |cookies_|, |pending_|, |num_pending_|, |force_keep_session_state_| 238 // Guard |cookies_|, |pending_|, |num_pending_|, |force_keep_session_state_|
202 base::Lock lock_; 239 base::Lock lock_;
203 240
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 int total_priority_requests_; 277 int total_priority_requests_;
241 // The time when |num_priority_waiting_| incremented to 1. 278 // The time when |num_priority_waiting_| incremented to 1.
242 base::Time current_priority_wait_start_; 279 base::Time current_priority_wait_start_;
243 // The cumulative duration of time when |num_priority_waiting_| was greater 280 // The cumulative duration of time when |num_priority_waiting_| was greater
244 // than 1. 281 // than 1.
245 base::TimeDelta priority_wait_duration_; 282 base::TimeDelta priority_wait_duration_;
246 283
247 DISALLOW_COPY_AND_ASSIGN(Backend); 284 DISALLOW_COPY_AND_ASSIGN(Backend);
248 }; 285 };
249 286
287 SQLitePersistentCookieStore::Backend::KillDatabaseErrorDelegate::
288 KillDatabaseErrorDelegate(Backend* backend,
289 sql::ErrorDelegate* wrapped_delegate)
290 : backend_(backend),
291 wrapped_delegate_(wrapped_delegate) {
292 }
293
294 int SQLitePersistentCookieStore::Backend::KillDatabaseErrorDelegate::OnError(
295 int error, sql::Connection* connection, sql::Statement* stmt) {
296 if (wrapped_delegate_.get())
297 error = wrapped_delegate_->OnError(error, connection, stmt);
298
299 bool delete_db = false;
300
301 switch (error) {
302 case SQLITE_DONE:
303 case SQLITE_OK:
304 // Theoretically, the wrapped delegate might have resolved the error, and
305 // we would end up here.
306 break;
307
308 case SQLITE_CORRUPT:
309 case SQLITE_NOTADB:
310 // Highly unlikely we would ever recover from these.
311 delete_db = true;
312 break;
313
314 case SQLITE_CANTOPEN:
315 // TODO(erikwright): Figure out what this means.
316 break;
317
318 case SQLITE_IOERR:
319 // This could be broken blocks, in which case deleting the DB would be a
320 // good idea. But it might also be transient.
321 // TODO(erikwright): Figure out if we can distinguish between the two,
322 // or determine through metrics analysis to what extent these failures are
323 // transient.
324 break;
325
326 case SQLITE_BUSY:
327 // Presumably transient.
328 break;
329
330 case SQLITE_TOOBIG:
331 case SQLITE_FULL:
332 case SQLITE_NOMEM:
333 // Not a problem with the database.
334 break;
335
336 case SQLITE_READONLY:
337 // Presumably either transient or we don't have the privileges to
338 // move/delete the file anyway.
339 break;
340
341 case SQLITE_CONSTRAINT:
342 case SQLITE_ERROR:
343 // These probably indicate a programming error or a migration failure that
344 // we prefer not to mask.
345 break;
346
347 case SQLITE_LOCKED:
348 case SQLITE_INTERNAL:
349 case SQLITE_PERM:
350 case SQLITE_ABORT:
351 case SQLITE_INTERRUPT:
352 case SQLITE_NOTFOUND:
353 case SQLITE_PROTOCOL:
354 case SQLITE_EMPTY:
355 case SQLITE_SCHEMA:
356 case SQLITE_MISMATCH:
357 case SQLITE_MISUSE:
358 case SQLITE_NOLFS:
359 case SQLITE_AUTH:
360 case SQLITE_FORMAT:
361 case SQLITE_RANGE:
362 case SQLITE_ROW:
363 // None of these appear in error reports, so for now let's not try to
364 // guess at how to handle them.
365 break;
366 }
367
368 if (delete_db && backend_) {
369 // Don't just do the close/delete here, as we are being called by |db| and
370 // that seems dangerous.
371 MessageLoop::current()->PostTask(
372 FROM_HERE, base::Bind(&Backend::KillDatabase, backend_));
373
374 // Avoid being called more than once. There should still be a reference to
375 // this ErrorDelegate in the backend, but just in case don't refer to any
376 // members from here forward.
377 connection->set_error_delegate(wrapped_delegate_.get());
378 }
379
380 return error;
381 }
382
250 // Version number of the database. 383 // Version number of the database.
251 // 384 //
252 // Version 5 adds the columns has_expires and is_persistent, so that the 385 // Version 5 adds the columns has_expires and is_persistent, so that the
253 // database can store session cookies as well as persistent cookies. Databases 386 // database can store session cookies as well as persistent cookies. Databases
254 // of version 5 are incompatible with older versions of code. If a database of 387 // of version 5 are incompatible with older versions of code. If a database of
255 // version 5 is read by older code, session cookies will be treated as normal 388 // version 5 is read by older code, session cookies will be treated as normal
256 // cookies. Currently, these fields are written, but not read anymore. 389 // cookies. Currently, these fields are written, but not read anymore.
257 // 390 //
258 // In version 4, we migrated the time epoch. If you open the DB with an older 391 // In version 4, we migrated the time epoch. If you open the DB with an older
259 // version on Mac or Linux, the times will look wonky, but the file will likely 392 // version on Mac or Linux, the times will look wonky, but the file will likely
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
487 return false; 620 return false;
488 } 621 }
489 622
490 int64 db_size = 0; 623 int64 db_size = 0;
491 if (file_util::GetFileSize(path_, &db_size)) { 624 if (file_util::GetFileSize(path_, &db_size)) {
492 base::ThreadRestrictions::ScopedAllowIO allow_io; 625 base::ThreadRestrictions::ScopedAllowIO allow_io;
493 UMA_HISTOGRAM_COUNTS("Cookie.DBSizeInKB", db_size / 1024 ); 626 UMA_HISTOGRAM_COUNTS("Cookie.DBSizeInKB", db_size / 1024 );
494 } 627 }
495 628
496 db_.reset(new sql::Connection); 629 db_.reset(new sql::Connection);
630 db_->set_error_delegate(error_delegate_.get());
631
497 if (!db_->Open(path_)) { 632 if (!db_->Open(path_)) {
498 NOTREACHED() << "Unable to open cookie DB."; 633 NOTREACHED() << "Unable to open cookie DB.";
499 db_.reset(); 634 db_.reset();
500 return false; 635 return false;
501 } 636 }
502 637
503 db_->set_error_delegate(GetErrorHandlerForCookieDb());
504
505 if (!EnsureDatabaseVersion() || !InitTable(db_.get())) { 638 if (!EnsureDatabaseVersion() || !InitTable(db_.get())) {
506 NOTREACHED() << "Unable to open cookie DB."; 639 NOTREACHED() << "Unable to open cookie DB.";
507 db_.reset(); 640 db_.reset();
508 return false; 641 return false;
509 } 642 }
510 643
511 UMA_HISTOGRAM_CUSTOM_TIMES( 644 UMA_HISTOGRAM_CUSTOM_TIMES(
512 "Cookie.TimeInitializeDB", 645 "Cookie.TimeInitializeDB",
513 base::Time::Now() - start, 646 base::Time::Now() - start,
514 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 647 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after
961 del_smt.BindString(0, it->first.first); 1094 del_smt.BindString(0, it->first.first);
962 del_smt.BindInt(1, it->first.second); 1095 del_smt.BindInt(1, it->first.second);
963 if (!del_smt.Run()) 1096 if (!del_smt.Run())
964 NOTREACHED() << "Could not delete a cookie from the DB."; 1097 NOTREACHED() << "Could not delete a cookie from the DB.";
965 } 1098 }
966 1099
967 if (!transaction.Commit()) 1100 if (!transaction.Commit())
968 LOG(WARNING) << "Unable to delete cookies on shutdown."; 1101 LOG(WARNING) << "Unable to delete cookies on shutdown.";
969 } 1102 }
970 1103
1104 void SQLitePersistentCookieStore::Backend::KillDatabase() {
1105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
1106
1107 if (db_.get()) {
1108 // This Backend will now be in-memory only. In a future run we will recreate
1109 // the database. Hopefully things go better then!
1110 bool success = db_->Raze();
1111 UMA_HISTOGRAM_BOOLEAN("Cookie.KillDatabaseResult", success);
1112 db_->Close();
1113 db_.reset();
1114 }
1115 }
1116
971 void SQLitePersistentCookieStore::Backend::SetForceKeepSessionState() { 1117 void SQLitePersistentCookieStore::Backend::SetForceKeepSessionState() {
972 base::AutoLock locked(lock_); 1118 base::AutoLock locked(lock_);
973 force_keep_session_state_ = true; 1119 force_keep_session_state_ = true;
974 } 1120 }
975 1121
976 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() { 1122 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() {
977 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 1123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
978 if (!db_->Execute("DELETE FROM cookies WHERE persistent == 0")) 1124 if (!db_->Execute("DELETE FROM cookies WHERE persistent == 0"))
979 LOG(WARNING) << "Unable to delete session cookies."; 1125 LOG(WARNING) << "Unable to delete session cookies.";
980 } 1126 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1026 } 1172 }
1027 1173
1028 SQLitePersistentCookieStore::~SQLitePersistentCookieStore() { 1174 SQLitePersistentCookieStore::~SQLitePersistentCookieStore() {
1029 if (backend_.get()) { 1175 if (backend_.get()) {
1030 backend_->Close(); 1176 backend_->Close();
1031 // Release our reference, it will probably still have a reference if the 1177 // Release our reference, it will probably still have a reference if the
1032 // background thread has not run Close() yet. 1178 // background thread has not run Close() yet.
1033 backend_ = NULL; 1179 backend_ = NULL;
1034 } 1180 }
1035 } 1181 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698