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

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: Raze instead of deleting. 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 private:
124 // Do not increment the count on Backend, as that would create a circular
125 // reference (Backend -> Connection -> ErrorDelegate -> Backend). Instead,
126 // Backend will call reset_backend() when it is going away.
127 Backend* backend_;
128 scoped_refptr<sql::ErrorDelegate> wrapped_delegate_;
129
130 DISALLOW_COPY_AND_ASSIGN(KillDatabaseErrorDelegate);
131 };
132
107 // You should call Close() before destructing this object. 133 // You should call Close() before destructing this object.
108 ~Backend() { 134 ~Backend() {
109 DCHECK(!db_.get()) << "Close should have already been called."; 135 DCHECK(!db_.get()) << "Close should have already been called.";
110 DCHECK(num_pending_ == 0 && pending_.empty()); 136 DCHECK(num_pending_ == 0 && pending_.empty());
111 } 137 }
112 138
113 // Database upgrade statements. 139 // Database upgrade statements.
114 bool EnsureDatabaseVersion(); 140 bool EnsureDatabaseVersion();
115 141
116 class PendingOperation { 142 class PendingOperation {
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 const net::CanonicalCookie& cc); 208 const net::CanonicalCookie& cc);
183 // Commit our pending operations to the database. 209 // Commit our pending operations to the database.
184 void Commit(); 210 void Commit();
185 // Close() executed on the background thread. 211 // Close() executed on the background thread.
186 void InternalBackgroundClose(); 212 void InternalBackgroundClose();
187 213
188 void DeleteSessionCookiesOnStartup(); 214 void DeleteSessionCookiesOnStartup();
189 215
190 void DeleteSessionCookiesOnShutdown(); 216 void DeleteSessionCookiesOnShutdown();
191 217
218 void KillDatabase();
219
192 FilePath path_; 220 FilePath path_;
193 scoped_ptr<sql::Connection> db_; 221 scoped_ptr<sql::Connection> db_;
222 scoped_refptr<KillDatabaseErrorDelegate> error_delegate_;
194 sql::MetaTable meta_table_; 223 sql::MetaTable meta_table_;
195 224
196 typedef std::list<PendingOperation*> PendingOperationsList; 225 typedef std::list<PendingOperation*> PendingOperationsList;
197 PendingOperationsList pending_; 226 PendingOperationsList pending_;
198 PendingOperationsList::size_type num_pending_; 227 PendingOperationsList::size_type num_pending_;
199 // True if the persistent store should skip delete on exit rules. 228 // True if the persistent store should skip delete on exit rules.
200 bool force_keep_session_state_; 229 bool force_keep_session_state_;
201 // Guard |cookies_|, |pending_|, |num_pending_|, |force_keep_session_state_| 230 // Guard |cookies_|, |pending_|, |num_pending_|, |force_keep_session_state_|
202 base::Lock lock_; 231 base::Lock lock_;
203 232
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 int total_priority_requests_; 269 int total_priority_requests_;
241 // The time when |num_priority_waiting_| incremented to 1. 270 // The time when |num_priority_waiting_| incremented to 1.
242 base::Time current_priority_wait_start_; 271 base::Time current_priority_wait_start_;
243 // The cumulative duration of time when |num_priority_waiting_| was greater 272 // The cumulative duration of time when |num_priority_waiting_| was greater
244 // than 1. 273 // than 1.
245 base::TimeDelta priority_wait_duration_; 274 base::TimeDelta priority_wait_duration_;
246 275
247 DISALLOW_COPY_AND_ASSIGN(Backend); 276 DISALLOW_COPY_AND_ASSIGN(Backend);
248 }; 277 };
249 278
279 SQLitePersistentCookieStore::Backend::KillDatabaseErrorDelegate::
280 KillDatabaseErrorDelegate(Backend* backend,
281 sql::ErrorDelegate* wrapped_delegate)
282 : backend_(backend),
283 wrapped_delegate_(wrapped_delegate) {
284 }
285
286 int SQLitePersistentCookieStore::Backend::KillDatabaseErrorDelegate::OnError(
287 int error, sql::Connection* connection, sql::Statement* stmt) {
288 if (wrapped_delegate_.get())
289 error = wrapped_delegate_->OnError(error, connection, stmt);
290
291 bool delete_db = false;
292
293 switch (error) {
294 case SQLITE_DONE:
295 case SQLITE_OK:
296 // Theoretically, the wrapped delegate might have resolved the error, and
297 // we would end up here.
298 break;
299
300 case SQLITE_CORRUPT:
301 case SQLITE_NOTADB:
302 // Highly unlikely we would ever recover from these.
303 delete_db = true;
304 break;
305
306 case SQLITE_CANTOPEN:
307 // TODO(erikwright): Figure out what this means.
308 break;
309
310 case SQLITE_IOERR:
311 // This could be broken blocks, in which case deleting the DB would be a
312 // good idea. But it might also be transient.
313 // TODO(erikwright): Figure out if we can distinguish between the two,
314 // or determine through metrics analysis to what extent these failures are
315 // transient.
316 break;
317
318 case SQLITE_BUSY:
319 // Presumably transient.
320 break;
321
322 case SQLITE_TOOBIG:
323 case SQLITE_FULL:
324 case SQLITE_NOMEM:
325 // Not a problem with the database.
326 break;
327
328 case SQLITE_READONLY:
329 // Presumably either transient or we don't have the privileges to
330 // move/delete the file anyway.
331 break;
332
333 case SQLITE_CONSTRAINT:
334 case SQLITE_ERROR:
335 // These probably indicate a programming error or a migration failure that
336 // we prefer not to mask.
337 break;
338
339 case SQLITE_LOCKED:
340 case SQLITE_INTERNAL:
341 case SQLITE_PERM:
342 case SQLITE_ABORT:
343 case SQLITE_INTERRUPT:
344 case SQLITE_NOTFOUND:
345 case SQLITE_PROTOCOL:
346 case SQLITE_EMPTY:
347 case SQLITE_SCHEMA:
348 case SQLITE_MISMATCH:
349 case SQLITE_MISUSE:
350 case SQLITE_NOLFS:
351 case SQLITE_AUTH:
352 case SQLITE_FORMAT:
353 case SQLITE_RANGE:
354 case SQLITE_ROW:
355 // None of these appear in error reports, so for now let's not try to
356 // guess at how to handle them.
357 break;
358 }
359
360 if (delete_db && backend_) {
361 // Don't just do the close/delete here, as we are being called by |db| and
362 // that seems dangerous.
363 MessageLoop::current()->PostTask(
364 FROM_HERE, base::Bind(&Backend::KillDatabase, backend_));
365
366 // Avoid being called more than once. There should still be a reference to
367 // this ErrorDelegate in the backend, but just in case don't refer to any
368 // members from here forward.
369 connection->set_error_delegate(wrapped_delegate_.get());
370 }
371
372 return error;
373 }
374
250 // Version number of the database. 375 // Version number of the database.
251 // 376 //
252 // Version 5 adds the columns has_expires and is_persistent, so that the 377 // 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 378 // 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 379 // 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 380 // 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. 381 // cookies. Currently, these fields are written, but not read anymore.
257 // 382 //
258 // In version 4, we migrated the time epoch. If you open the DB with an older 383 // 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 384 // 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; 612 return false;
488 } 613 }
489 614
490 int64 db_size = 0; 615 int64 db_size = 0;
491 if (file_util::GetFileSize(path_, &db_size)) { 616 if (file_util::GetFileSize(path_, &db_size)) {
492 base::ThreadRestrictions::ScopedAllowIO allow_io; 617 base::ThreadRestrictions::ScopedAllowIO allow_io;
493 UMA_HISTOGRAM_COUNTS("Cookie.DBSizeInKB", db_size / 1024 ); 618 UMA_HISTOGRAM_COUNTS("Cookie.DBSizeInKB", db_size / 1024 );
494 } 619 }
495 620
496 db_.reset(new sql::Connection); 621 db_.reset(new sql::Connection);
622 db_->set_error_delegate(error_delegate_.get());
623
497 if (!db_->Open(path_)) { 624 if (!db_->Open(path_)) {
498 NOTREACHED() << "Unable to open cookie DB."; 625 NOTREACHED() << "Unable to open cookie DB.";
499 db_.reset(); 626 db_.reset();
500 return false; 627 return false;
501 } 628 }
502 629
503 db_->set_error_delegate(GetErrorHandlerForCookieDb());
504
505 if (!EnsureDatabaseVersion() || !InitTable(db_.get())) { 630 if (!EnsureDatabaseVersion() || !InitTable(db_.get())) {
506 NOTREACHED() << "Unable to open cookie DB."; 631 NOTREACHED() << "Unable to open cookie DB.";
507 db_.reset(); 632 db_.reset();
508 return false; 633 return false;
509 } 634 }
510 635
511 UMA_HISTOGRAM_CUSTOM_TIMES( 636 UMA_HISTOGRAM_CUSTOM_TIMES(
512 "Cookie.TimeInitializeDB", 637 "Cookie.TimeInitializeDB",
513 base::Time::Now() - start, 638 base::Time::Now() - start,
514 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 639 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after
918 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 1043 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
919 // Commit any pending operations 1044 // Commit any pending operations
920 Commit(); 1045 Commit();
921 1046
922 if (!force_keep_session_state_ && clear_on_exit_policy_.get() && 1047 if (!force_keep_session_state_ && clear_on_exit_policy_.get() &&
923 clear_on_exit_policy_->HasClearOnExitOrigins()) { 1048 clear_on_exit_policy_->HasClearOnExitOrigins()) {
924 DeleteSessionCookiesOnShutdown(); 1049 DeleteSessionCookiesOnShutdown();
925 } 1050 }
926 1051
927 db_.reset(); 1052 db_.reset();
1053 if (error_delegate_.get()) {
1054 error_delegate_->reset_backend();
1055 error_delegate_ = NULL;
1056 }
928 } 1057 }
929 1058
930 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnShutdown() { 1059 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnShutdown() {
931 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 1060 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
932 1061
933 if (!db_.get()) 1062 if (!db_.get())
934 return; 1063 return;
935 1064
936 sql::Statement del_smt(db_->GetCachedStatement( 1065 sql::Statement del_smt(db_->GetCachedStatement(
937 SQL_FROM_HERE, "DELETE FROM cookies WHERE host_key=? AND secure=?")); 1066 SQL_FROM_HERE, "DELETE FROM cookies WHERE host_key=? AND secure=?"));
(...skipping 23 matching lines...) Expand all
961 del_smt.BindString(0, it->first.first); 1090 del_smt.BindString(0, it->first.first);
962 del_smt.BindInt(1, it->first.second); 1091 del_smt.BindInt(1, it->first.second);
963 if (!del_smt.Run()) 1092 if (!del_smt.Run())
964 NOTREACHED() << "Could not delete a cookie from the DB."; 1093 NOTREACHED() << "Could not delete a cookie from the DB.";
965 } 1094 }
966 1095
967 if (!transaction.Commit()) 1096 if (!transaction.Commit())
968 LOG(WARNING) << "Unable to delete cookies on shutdown."; 1097 LOG(WARNING) << "Unable to delete cookies on shutdown.";
969 } 1098 }
970 1099
1100 void SQLitePersistentCookieStore::Backend::KillDatabase() {
1101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
1102
1103 if (db_.get()) {
1104 // This Backend will now be in-memory only. In a future run we will recreate
1105 // the database. Hopefully things go better then!
1106 bool success = db_->Raze();
1107 UMA_HISTOGRAM_BOOLEAN("Cookie.KillDatabaseResult", success);
1108 db_->Close();
1109 db_.reset();
1110 }
Scott Hess - ex-Googler 2012/09/14 18:34:03 Would it be worthwhile to document the no-db_ case
1111 }
1112
971 void SQLitePersistentCookieStore::Backend::SetForceKeepSessionState() { 1113 void SQLitePersistentCookieStore::Backend::SetForceKeepSessionState() {
972 base::AutoLock locked(lock_); 1114 base::AutoLock locked(lock_);
973 force_keep_session_state_ = true; 1115 force_keep_session_state_ = true;
974 } 1116 }
975 1117
976 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() { 1118 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() {
977 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 1119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
978 if (!db_->Execute("DELETE FROM cookies WHERE persistent == 0")) 1120 if (!db_->Execute("DELETE FROM cookies WHERE persistent == 0"))
979 LOG(WARNING) << "Unable to delete session cookies."; 1121 LOG(WARNING) << "Unable to delete session cookies.";
980 } 1122 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1026 } 1168 }
1027 1169
1028 SQLitePersistentCookieStore::~SQLitePersistentCookieStore() { 1170 SQLitePersistentCookieStore::~SQLitePersistentCookieStore() {
1029 if (backend_.get()) { 1171 if (backend_.get()) {
1030 backend_->Close(); 1172 backend_->Close();
1031 // Release our reference, it will probably still have a reference if the 1173 // Release our reference, it will probably still have a reference if the
1032 // background thread has not run Close() yet. 1174 // background thread has not run Close() yet.
1033 backend_ = NULL; 1175 backend_ = NULL;
1034 } 1176 }
1035 } 1177 }
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