Support WebSQLDatabases in incognito mode.

BUG=43232
TEST=none

Review URL: http://codereview.chromium.org/2746003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49644 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index ea689e68..15ef278 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -316,6 +316,13 @@
                                            Source<Profile>(this),
                                            NotificationService::NoDetails());
     CleanupRequestContext(request_context_);
+
+    // Clean up all DB files/directories
+    ChromeThread::PostTask(
+        ChromeThread::FILE, FROM_HERE,
+        NewRunnableMethod(
+            db_tracker_.get(),
+            &webkit_database::DatabaseTracker::DeleteIncognitoDBDirectory));
   }
 
   virtual ProfileId GetRuntimeId() {
@@ -342,8 +349,10 @@
   }
 
   virtual webkit_database::DatabaseTracker* GetDatabaseTracker() {
-    if (!db_tracker_)
-      db_tracker_ = new webkit_database::DatabaseTracker(FilePath());
+    if (!db_tracker_) {
+      db_tracker_ = new webkit_database::DatabaseTracker(
+          GetPath(), IsOffTheRecord());
+    }
     return db_tracker_;
   }
 
@@ -1017,8 +1026,10 @@
 }
 
 webkit_database::DatabaseTracker* ProfileImpl::GetDatabaseTracker() {
-  if (!db_tracker_)
-    db_tracker_ = new webkit_database::DatabaseTracker(GetPath());
+  if (!db_tracker_) {
+    db_tracker_ = new webkit_database::DatabaseTracker(
+        GetPath(), IsOffTheRecord());
+  }
   return db_tracker_;
 }
 
diff --git a/chrome/browser/renderer_host/database_dispatcher_host.cc b/chrome/browser/renderer_host/database_dispatcher_host.cc
index f9f35285a..eb51fb98 100644
--- a/chrome/browser/renderer_host/database_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/database_dispatcher_host.cc
@@ -157,13 +157,19 @@
                                               int desired_flags,
                                               IPC::Message* reply_msg) {
   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+  base::PlatformFile file_handle = base::kInvalidPlatformFileValue;
   base::PlatformFile target_handle = base::kInvalidPlatformFileValue;
   string16 origin_identifier;
   string16 database_name;
+
+  // When in incognito mode, we want to make sure that all DB files are
+  // removed when the incognito profile goes away, so we add the
+  // SQLITE_OPEN_DELETEONCLOSE flag when opening all files, and keep
+  // open handles to them in the database tracker to make sure they're
+  // around for as long as needed.
   if (vfs_file_name.empty()) {
     VfsBackend::OpenTempFileInDirectory(db_tracker_->DatabaseDirectory(),
-                                        desired_flags, process_handle_,
-                                        &target_handle);
+                                        desired_flags, &file_handle);
   } else if (DatabaseUtil::CrackVfsFileName(vfs_file_name, &origin_identifier,
                                             &database_name, NULL) &&
              !db_tracker_->IsDatabaseScheduledForDeletion(origin_identifier,
@@ -171,17 +177,35 @@
       FilePath db_file =
           DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
       if (!db_file.empty()) {
-        VfsBackend::OpenFile(db_file, desired_flags, process_handle_,
-                             &target_handle);
+        if (db_tracker_->IsIncognitoProfile()) {
+          db_tracker_->GetIncognitoFileHandle(vfs_file_name, &file_handle);
+          if (file_handle == base::kInvalidPlatformFileValue) {
+            VfsBackend::OpenFile(db_file,
+                                 desired_flags | SQLITE_OPEN_DELETEONCLOSE,
+                                 &file_handle);
+            if (VfsBackend::FileTypeIsMainDB(desired_flags) ||
+                VfsBackend::FileTypeIsJournal(desired_flags))
+              db_tracker_->SaveIncognitoFileHandle(vfs_file_name, file_handle);
+          }
+        } else {
+          VfsBackend::OpenFile(db_file, desired_flags, &file_handle);
+        }
       }
   }
 
+  // Then we duplicate the file handle to make it useable in the renderer
+  // process. The original handle is closed, unless we saved it in the
+  // database tracker.
+  bool auto_close = !db_tracker_->HasSavedIncognitoFileHandle(vfs_file_name);
+  VfsBackend::GetFileHandleForProcess(process_handle_, file_handle,
+                                      &target_handle, auto_close);
+
   ViewHostMsg_DatabaseOpenFile::WriteReplyParams(
       reply_msg,
 #if defined(OS_WIN)
       target_handle
 #elif defined(OS_POSIX)
-      base::FileDescriptor(target_handle, true)
+      base::FileDescriptor(target_handle, auto_close)
 #endif
       );
   Send(reply_msg);
@@ -216,7 +240,15 @@
   FilePath db_file =
       DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
   if (!db_file.empty()) {
-    error_code = VfsBackend::DeleteFile(db_file, sync_dir);
+    // In order to delete a journal file in incognito mode, we only need to
+    // close the open handle to it that's stored in the database tracker.
+    if (db_tracker_->IsIncognitoProfile()) {
+      if (db_tracker_->CloseIncognitoFileHandle(vfs_file_name))
+        error_code = SQLITE_OK;
+    } else {
+      error_code = VfsBackend::DeleteFile(db_file, sync_dir);
+    }
+
     if ((error_code == SQLITE_IOERR_DELETE) && reschedule_count) {
       // If the file could not be deleted, try again.
       ChromeThread::PostDelayedTask(
diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc
index 44811057..3d8ea0d 100644
--- a/chrome/test/testing_profile.cc
+++ b/chrome/test/testing_profile.cc
@@ -288,7 +288,7 @@
 
 webkit_database::DatabaseTracker* TestingProfile::GetDatabaseTracker() {
   if (!db_tracker_)
-    db_tracker_ = new webkit_database::DatabaseTracker(GetPath());
+    db_tracker_ = new webkit_database::DatabaseTracker(GetPath(), false);
   return db_tracker_;
 }