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

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: style. 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.
Scott Hess - ex-Googler 2012/09/14 17:15:16 Rather than doing this dance, would it make sense
erikwright (departed) 2012/09/14 18:11:02 Then you would have the circular reference of Back
Scott Hess - ex-Googler 2012/09/14 18:34:03 Doh!
erikwright (departed) 2012/09/14 18:43:26 We hold a pointer to the KillDatabaseErrorDelegate
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
307 case SQLITE_ERROR:
Scott Hess - ex-Googler 2012/09/14 17:01:34 This an SQLITE_CONSTRAINT are _probably_ cases whe
308 // TODO(erikwright): Figure out whether this is likely to be recoverable.
309 break;
310
311 case SQLITE_CANTOPEN:
312 // TODO(erikwright): Figure out what this means.
313 break;
Scott Hess - ex-Googler 2012/09/14 17:01:34 Dammit, I wish I remember where I was seeing this,
314
315 case SQLITE_IOERR:
316 case SQLITE_BUSY:
317 // Presumably transient.
318 break;
Scott Hess - ex-Googler 2012/09/14 17:01:34 It is possible to write the code such that SQLITE_
erikwright (departed) 2012/09/14 18:11:02 SQLITE_IOERR is a relatively commonly occurring er
319
320 case SQLITE_TOOBIG:
321 case SQLITE_FULL:
322 case SQLITE_NOMEM:
323 // Not a problem with the database.
324 break;
325
326 case SQLITE_READONLY:
327 // Presumably either transient or we don't have the privileges to
328 // move/delete the file anyway.
329 break;
Scott Hess - ex-Googler 2012/09/14 17:01:34 We might be able to delete a read-only file. Depe
erikwright (departed) 2012/09/14 18:11:02 It is a commonly occuring error. Again, I'll dig i
330
331 case SQLITE_CONSTRAINT:
332 // Presumably there is a schema upgrade failure.
333 // TODO(erikwright): Shall we kill the DB as an easy way out?
334 break;
335
336 case SQLITE_LOCKED:
337 case SQLITE_INTERNAL:
338 case SQLITE_PERM:
339 case SQLITE_ABORT:
340 case SQLITE_INTERRUPT:
341 case SQLITE_NOTFOUND:
342 case SQLITE_PROTOCOL:
343 case SQLITE_EMPTY:
344 case SQLITE_SCHEMA:
345 case SQLITE_MISMATCH:
346 case SQLITE_MISUSE:
347 case SQLITE_NOLFS:
348 case SQLITE_AUTH:
349 case SQLITE_FORMAT:
350 case SQLITE_RANGE:
351 case SQLITE_ROW:
352 // None of these appear in error reports, so for now let's not try to
353 // guess at how to handle them.
354 break;
355 }
356
357 if (delete_db && backend_) {
358 // Don't just do the close/delete here, as we are being called by |db| and
359 // that seems dangerous.
360 MessageLoop::current()->PostTask(
361 FROM_HERE, base::Bind(&Backend::KillDatabase, backend_));
362
363 // Avoid being called more than once. There should still be a reference to
364 // this ErrorDelegate in the backend, but just in case don't refer to any
365 // members from here forward.
366 connection->set_error_delegate(wrapped_delegate_.get());
367 }
368
369 return error;
370 }
371
250 // Version number of the database. 372 // Version number of the database.
251 // 373 //
252 // Version 5 adds the columns has_expires and is_persistent, so that the 374 // 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 375 // 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 376 // 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 377 // 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. 378 // cookies. Currently, these fields are written, but not read anymore.
257 // 379 //
258 // In version 4, we migrated the time epoch. If you open the DB with an older 380 // 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 381 // 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; 609 return false;
488 } 610 }
489 611
490 int64 db_size = 0; 612 int64 db_size = 0;
491 if (file_util::GetFileSize(path_, &db_size)) { 613 if (file_util::GetFileSize(path_, &db_size)) {
492 base::ThreadRestrictions::ScopedAllowIO allow_io; 614 base::ThreadRestrictions::ScopedAllowIO allow_io;
493 UMA_HISTOGRAM_COUNTS("Cookie.DBSizeInKB", db_size / 1024 ); 615 UMA_HISTOGRAM_COUNTS("Cookie.DBSizeInKB", db_size / 1024 );
494 } 616 }
495 617
496 db_.reset(new sql::Connection); 618 db_.reset(new sql::Connection);
619 db_->set_error_delegate(error_delegate_.get());
620
497 if (!db_->Open(path_)) { 621 if (!db_->Open(path_)) {
498 NOTREACHED() << "Unable to open cookie DB."; 622 NOTREACHED() << "Unable to open cookie DB.";
499 db_.reset(); 623 db_.reset();
500 return false; 624 return false;
501 } 625 }
502 626
503 db_->set_error_delegate(GetErrorHandlerForCookieDb());
504
505 if (!EnsureDatabaseVersion() || !InitTable(db_.get())) { 627 if (!EnsureDatabaseVersion() || !InitTable(db_.get())) {
506 NOTREACHED() << "Unable to open cookie DB."; 628 NOTREACHED() << "Unable to open cookie DB.";
507 db_.reset(); 629 db_.reset();
508 return false; 630 return false;
509 } 631 }
510 632
511 UMA_HISTOGRAM_CUSTOM_TIMES( 633 UMA_HISTOGRAM_CUSTOM_TIMES(
512 "Cookie.TimeInitializeDB", 634 "Cookie.TimeInitializeDB",
513 base::Time::Now() - start, 635 base::Time::Now() - start,
514 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 636 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)); 1040 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
919 // Commit any pending operations 1041 // Commit any pending operations
920 Commit(); 1042 Commit();
921 1043
922 if (!force_keep_session_state_ && clear_on_exit_policy_.get() && 1044 if (!force_keep_session_state_ && clear_on_exit_policy_.get() &&
923 clear_on_exit_policy_->HasClearOnExitOrigins()) { 1045 clear_on_exit_policy_->HasClearOnExitOrigins()) {
924 DeleteSessionCookiesOnShutdown(); 1046 DeleteSessionCookiesOnShutdown();
925 } 1047 }
926 1048
927 db_.reset(); 1049 db_.reset();
1050 if (error_delegate_.get()) {
1051 error_delegate_->reset_backend();
1052 error_delegate_ = NULL;
1053 }
928 } 1054 }
929 1055
930 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnShutdown() { 1056 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnShutdown() {
931 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 1057 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
932 1058
933 if (!db_.get()) 1059 if (!db_.get())
934 return; 1060 return;
935 1061
936 sql::Statement del_smt(db_->GetCachedStatement( 1062 sql::Statement del_smt(db_->GetCachedStatement(
937 SQL_FROM_HERE, "DELETE FROM cookies WHERE host_key=? AND secure=?")); 1063 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); 1087 del_smt.BindString(0, it->first.first);
962 del_smt.BindInt(1, it->first.second); 1088 del_smt.BindInt(1, it->first.second);
963 if (!del_smt.Run()) 1089 if (!del_smt.Run())
964 NOTREACHED() << "Could not delete a cookie from the DB."; 1090 NOTREACHED() << "Could not delete a cookie from the DB.";
965 } 1091 }
966 1092
967 if (!transaction.Commit()) 1093 if (!transaction.Commit())
968 LOG(WARNING) << "Unable to delete cookies on shutdown."; 1094 LOG(WARNING) << "Unable to delete cookies on shutdown.";
969 } 1095 }
970 1096
1097 void SQLitePersistentCookieStore::Backend::KillDatabase() {
1098 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
1099
1100 if (db_.get()) {
1101 // This Backend will now be in-memory only. In a future run we will recreate
1102 // the database. Hopefully things go better then!
1103 db_->Close();
1104 db_.reset();
1105 }
1106
1107 bool success = file_util::Delete(path_, false);
Scott Hess - ex-Googler 2012/09/14 17:01:34 Suggest doing db_.Raze() before closing it. That
erikwright (departed) 2012/09/14 18:11:02 We can do the Raze for now and see what happens. W
1108 UMA_HISTOGRAM_BOOLEAN("Cookie.KillDatabaseResult", success);
1109 }
1110
971 void SQLitePersistentCookieStore::Backend::SetForceKeepSessionState() { 1111 void SQLitePersistentCookieStore::Backend::SetForceKeepSessionState() {
972 base::AutoLock locked(lock_); 1112 base::AutoLock locked(lock_);
973 force_keep_session_state_ = true; 1113 force_keep_session_state_ = true;
974 } 1114 }
975 1115
976 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() { 1116 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() {
977 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 1117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
978 if (!db_->Execute("DELETE FROM cookies WHERE persistent == 0")) 1118 if (!db_->Execute("DELETE FROM cookies WHERE persistent == 0"))
979 LOG(WARNING) << "Unable to delete session cookies."; 1119 LOG(WARNING) << "Unable to delete session cookies.";
980 } 1120 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1026 } 1166 }
1027 1167
1028 SQLitePersistentCookieStore::~SQLitePersistentCookieStore() { 1168 SQLitePersistentCookieStore::~SQLitePersistentCookieStore() {
1029 if (backend_.get()) { 1169 if (backend_.get()) {
1030 backend_->Close(); 1170 backend_->Close();
1031 // Release our reference, it will probably still have a reference if the 1171 // Release our reference, it will probably still have a reference if the
1032 // background thread has not run Close() yet. 1172 // background thread has not run Close() yet.
1033 backend_ = NULL; 1173 backend_ = NULL;
1034 } 1174 }
1035 } 1175 }
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