diff options
-rw-r--r-- | chrome/DEPS | 3 | ||||
-rw-r--r-- | chrome/browser/automation/automation_profile_impl.h | 3 | ||||
-rw-r--r-- | chrome/browser/profile.cc | 17 | ||||
-rw-r--r-- | chrome/browser/profile.h | 12 | ||||
-rw-r--r-- | chrome/browser/renderer_host/browser_render_process_host.cc | 16 | ||||
-rw-r--r-- | chrome/browser/renderer_host/database_dispatcher_host.cc | 513 | ||||
-rw-r--r-- | chrome/browser/renderer_host/database_dispatcher_host.h | 118 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 9 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 8 | ||||
-rw-r--r-- | chrome/common/db_message_filter.cc | 10 | ||||
-rw-r--r-- | chrome/common/db_message_filter.h | 10 | ||||
-rw-r--r-- | chrome/test/testing_profile.cc | 7 | ||||
-rw-r--r-- | chrome/test/testing_profile.h | 10 |
13 files changed, 503 insertions, 233 deletions
diff --git a/chrome/DEPS b/chrome/DEPS index ca6752e..1e982a0 100644 --- a/chrome/DEPS +++ b/chrome/DEPS @@ -21,6 +21,9 @@ include_rules = [ # Allow inclusion of the appcache library. "+webkit/appcache", + # Allow inclusion of the database library. + "+webkit/database", + # Allow inclusion of Mozilla interface headers. "+third_party/mozilla", diff --git a/chrome/browser/automation/automation_profile_impl.h b/chrome/browser/automation/automation_profile_impl.h index 54abd4c..0151193 100644 --- a/chrome/browser/automation/automation_profile_impl.h +++ b/chrome/browser/automation/automation_profile_impl.h @@ -51,6 +51,9 @@ class AutomationProfileImpl : public Profile { virtual Profile* GetOriginalProfile() { return original_profile_->GetOriginalProfile(); } + virtual webkit_database::DatabaseTracker* GetDatabaseTracker() { + return original_profile_->GetDatabaseTracker(); + } virtual VisitedLinkMaster* GetVisitedLinkMaster() { return original_profile_->GetVisitedLinkMaster(); } diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index cbee927..9f62d39 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -55,6 +55,7 @@ #include "chrome/common/render_messages.h" #include "grit/locale_settings.h" #include "net/base/strict_transport_security_state.h" +#include "webkit/database/database_tracker.h" #if defined(OS_LINUX) #include "net/ocsp/nss_ocsp.h" @@ -237,6 +238,12 @@ class OffTheRecordProfileImpl : public Profile, return profile_; } + virtual webkit_database::DatabaseTracker* GetDatabaseTracker() { + if (!db_tracker_) + db_tracker_ = new webkit_database::DatabaseTracker(FilePath()); + return db_tracker_; + } + virtual VisitedLinkMaster* GetVisitedLinkMaster() { // We don't provide access to the VisitedLinkMaster when we're OffTheRecord // because we don't want to leak the sites that the user has visited before. @@ -565,6 +572,10 @@ class OffTheRecordProfileImpl : public Profile, // Time we were started. Time start_time_; + // The main database tracker for this profile. + // Should be used only on the file thread. + scoped_refptr<webkit_database::DatabaseTracker> db_tracker_; + DISALLOW_COPY_AND_ASSIGN(OffTheRecordProfileImpl); }; @@ -830,6 +841,12 @@ Profile* ProfileImpl::GetOriginalProfile() { return this; } +webkit_database::DatabaseTracker* ProfileImpl::GetDatabaseTracker() { + if (!db_tracker_) + db_tracker_ = new webkit_database::DatabaseTracker(GetPath()); + return db_tracker_; +} + VisitedLinkMaster* ProfileImpl::GetVisitedLinkMaster() { if (!visited_link_master_.get()) { scoped_ptr<VisitedLinkMaster> visited_links( diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index 659e1bd..7497e6d 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -29,6 +29,10 @@ class StrictTransportSecurityState; class SSLConfigService; } +namespace webkit_database { +class DatabaseTracker; +} + class Blacklist; class BookmarkModel; class BrowserThemeProvider; @@ -139,6 +143,9 @@ class Profile { // profile is not off the record. virtual Profile* GetOriginalProfile() = 0; + // Returns a pointer to the DatabaseTracker instance for this profile. + virtual webkit_database::DatabaseTracker* GetDatabaseTracker() = 0; + // Retrieves a pointer to the VisitedLinkMaster associated with this // profile. The VisitedLinkMaster is lazily created the first time // that this method is called. @@ -421,6 +428,7 @@ class ProfileImpl : public Profile, virtual Profile* GetOffTheRecordProfile(); virtual void DestroyOffTheRecordProfile(); virtual Profile* GetOriginalProfile(); + virtual webkit_database::DatabaseTracker* GetDatabaseTracker(); virtual VisitedLinkMaster* GetVisitedLinkMaster(); virtual UserScriptMaster* GetUserScriptMaster(); virtual SSLHostState* GetSSLHostState(); @@ -595,6 +603,10 @@ class ProfileImpl : public Profile, // GetSessionService won't recreate the SessionService. bool shutdown_session_service_; + // The main database tracker for this profile. + // Should be used only on the file thread. + scoped_refptr<webkit_database::DatabaseTracker> db_tracker_; + #if defined(OS_CHROMEOS) chromeos::Preferences chromeos_preferences_; #endif diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index 144fb37..212134a 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -545,7 +545,6 @@ void BrowserRenderProcessHost::PropogateBrowserCommandLineToRenderer( switches::kSimpleDataSource, switches::kEnableBenchmarking, switches::kInternalNaCl, - switches::kEnableDatabases, switches::kDisableByteRangeSupport, switches::kDisableWebSockets, switches::kDisableLocalStorage, @@ -562,12 +561,27 @@ void BrowserRenderProcessHost::PropogateBrowserCommandLineToRenderer( #endif }; + // Propagate the following switches to the renderer command line (along + // with any associated values) only if we're not in incognito mode. + static const char* const not_otr_switch_names[] = { + switches::kEnableDatabases, + }; + for (size_t i = 0; i < arraysize(switch_names); ++i) { if (browser_cmd.HasSwitch(switch_names[i])) { renderer_cmd->AppendSwitchWithValue(switch_names[i], browser_cmd.GetSwitchValueASCII(switch_names[i])); } } + + if (!profile()->IsOffTheRecord()) { + for (size_t i = 0; i < arraysize(not_otr_switch_names); ++i) { + if (browser_cmd.HasSwitch(not_otr_switch_names[i])) { + renderer_cmd->AppendSwitchWithValue(not_otr_switch_names[i], + browser_cmd.GetSwitchValueASCII(not_otr_switch_names[i])); + } + } + } } #if defined(OS_WIN) diff --git a/chrome/browser/renderer_host/database_dispatcher_host.cc b/chrome/browser/renderer_host/database_dispatcher_host.cc index c13f8c7..171a0ad 100644 --- a/chrome/browser/renderer_host/database_dispatcher_host.cc +++ b/chrome/browser/renderer_host/database_dispatcher_host.cc @@ -4,8 +4,8 @@ #include "chrome/browser/renderer_host/database_dispatcher_host.h" -#if defined(OS_WIN) -#include <windows.h> +#if defined(OS_POSIX) +#include "base/file_descriptor_posix.h" #endif #if defined(USE_SYSTEM_SQLITE) @@ -14,262 +14,403 @@ #include "third_party/sqlite/preprocessed/sqlite3.h" #endif +#include "base/string_util.h" +#include "base/thread.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_thread.h" -#include "chrome/browser/renderer_host/resource_message_filter.h" +#include "chrome/browser/renderer_host/browser_render_process_host.h" #include "chrome/common/render_messages.h" #include "webkit/database/vfs_backend.h" -#if defined(OS_POSIX) -#include "base/file_descriptor_posix.h" -#endif - +using webkit_database::DatabaseTracker; using webkit_database::VfsBackend; -const int kNumDeleteRetries = 3; +const int kNumDeleteRetries = 2; const int kDelayDeleteRetryMs = 100; -namespace { +DatabaseDispatcherHost::DatabaseDispatcherHost( + DatabaseTracker* db_tracker, + IPC::Message::Sender* message_sender, + base::ProcessHandle process_handle) + : db_tracker_(db_tracker), + message_sender_(message_sender), + process_handle_(process_handle), + observer_added_(false), + shutdown_(false) { + DCHECK(db_tracker_); + DCHECK(message_sender_); +} + +void DatabaseDispatcherHost::Shutdown() { + shutdown_ = true; + message_sender_ = NULL; + if (observer_added_) { + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, &DatabaseDispatcherHost::RemoveObserver)); + } +} + +void DatabaseDispatcherHost::AddObserver() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + db_tracker_->AddObserver(this); +} -struct OpenFileParams { - FilePath db_dir; - FilePath file_name; - int desired_flags; - base::ProcessHandle handle; -}; +void DatabaseDispatcherHost::RemoveObserver() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + db_tracker_->RemoveObserver(this); +} + +FilePath DatabaseDispatcherHost::GetDBFileFullPath( + const FilePath& vfs_file_name) { + // 'vfs_file_name' can be one of 3 things: + // 1. Empty string: It means the VFS wants to open a temp file. In this case + // we need to return the path to the directory that stores all databases. + // 2. origin_identifier/database_name: In this case, we need to extract + // 'origin_identifier' and 'database_name' and pass them to + // DatabaseTracker::GetFullDBFilePath(). + // 3. origin_identifier/database_name-suffix: '-suffix' could be '-journal', + // for example. In this case, we need to extract 'origin_identifier' and + // 'database_name-suffix' and pass them to + // DatabaseTracker::GetFullDBFilePath(). 'database_name-suffix' is not + // a database name as expected by DatabaseTracker::GetFullDBFilePath(), + // but due to its implementation, it's OK to pass in 'database_name-suffix' + // too. + // + // We also check that the given string doesn't contain invalid characters + // that would result in a DB file stored outside of the directory where + // all DB files are supposed to be stored. + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + if (vfs_file_name.empty()) + return db_tracker_->DatabaseDirectory(); + + std::wstring str = vfs_file_name.ToWStringHack(); + size_t slashIndex = str.find('/'); + if (slashIndex == std::wstring::npos) + return FilePath(); // incorrect format + std::wstring origin_identifier = str.substr(0, slashIndex); + std::wstring database_name = + str.substr(slashIndex + 1, str.length() - slashIndex); + if ((origin_identifier.find('\\') != std::wstring::npos) || + (origin_identifier.find('/') != std::wstring::npos) || + (origin_identifier.find(':') != std::wstring::npos) || + (database_name.find('\\') != std::wstring::npos) || + (database_name.find('/') != std::wstring::npos) || + (database_name.find(':') != std::wstring::npos)) { + return FilePath(); + } + + return db_tracker_->GetFullDBFilePath( + WideToUTF16(origin_identifier), WideToUTF16(database_name)); +} + +bool DatabaseDispatcherHost::OnMessageReceived( + const IPC::Message& message, bool* message_was_ok) { + DCHECK(!shutdown_); + *message_was_ok = true; + bool handled = true; + IPC_BEGIN_MESSAGE_MAP_EX(DatabaseDispatcherHost, message, *message_was_ok) + IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseOpenFile, OnDatabaseOpenFile) + IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseDeleteFile, OnDatabaseDeleteFile) + IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseGetFileAttributes, + OnDatabaseGetFileAttributes) + IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseGetFileSize, + OnDatabaseGetFileSize) + IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseOpened, OnDatabaseOpened) + IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseModified, OnDatabaseModified) + IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseClosed, OnDatabaseClosed) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP_EX() + return handled; +} -struct DeleteFileParams { - FilePath db_dir; - FilePath file_name; - bool sync_dir; -}; +void DatabaseDispatcherHost::ReceivedBadMessage(uint16 msg_type) { + BrowserRenderProcessHost::BadMessageTerminateProcess( + msg_type, process_handle_); +} -// Scheduled by the file Thread on the IO thread. +// Scheduled by the file thread on the IO thread. // Sends back to the renderer process the given message. -static void SendMessage(ResourceMessageFilter* sender, - IPC::Message* message) { - sender->Send(message); - - // Every time we get a DB-related message, we AddRef() the resource - // message filterto make sure it doesn't get destroyed before we have - // a chance to send the reply back. So we need to Release() is here - // and allow it to be destroyed if needed. - sender->Release(); +void DatabaseDispatcherHost::SendMessage(IPC::Message* message) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (!shutdown_) + message_sender_->Send(message); + else + delete message; +} + +void DatabaseDispatcherHost::OnDatabaseOpenFile(const FilePath& vfs_file_name, + int desired_flags, + int32 message_id) { + if (!observer_added_) { + observer_added_ = true; + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, &DatabaseDispatcherHost::AddObserver)); + } + + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, + &DatabaseDispatcherHost::DatabaseOpenFile, + vfs_file_name, + desired_flags, + message_id)); +} + +static void SetOpenFileResponseParams( + ViewMsg_DatabaseOpenFileResponse_Params* params, + base::PlatformFile file_handle, + base::PlatformFile dir_handle) { +#if defined(OS_WIN) + params->file_handle = file_handle; +#elif defined(OS_POSIX) + params->file_handle = base::FileDescriptor(file_handle, true); + params->dir_handle = base::FileDescriptor(dir_handle, true); +#endif } // Scheduled by the IO thread on the file thread. // Opens the given database file, then schedules // a task on the IO thread's message loop to send an IPC back to // corresponding renderer process with the file handle. -static void DatabaseOpenFile(const OpenFileParams& params, - int32 message_id, - ResourceMessageFilter* sender) { +void DatabaseDispatcherHost::DatabaseOpenFile(const FilePath& vfs_file_name, + int desired_flags, + int32 message_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); base::PlatformFile target_handle = base::kInvalidPlatformFileValue; base::PlatformFile target_dir_handle = base::kInvalidPlatformFileValue; - VfsBackend::OpenFile(params.file_name, params.db_dir, params.desired_flags, - params.handle, &target_handle, &target_dir_handle); + FilePath db_file_name = GetDBFileFullPath(vfs_file_name); + if (!db_file_name.empty()) { + FilePath db_dir = db_tracker_->DatabaseDirectory(); + VfsBackend::OpenFile(db_file_name, db_dir, desired_flags, + process_handle_, &target_handle, &target_dir_handle); + } ViewMsg_DatabaseOpenFileResponse_Params response_params; -#if defined(OS_WIN) - response_params.file_handle = target_handle; -#elif defined(OS_POSIX) - response_params.file_handle = base::FileDescriptor(target_handle, true); - response_params.dir_handle = base::FileDescriptor(target_dir_handle, true); -#endif + SetOpenFileResponseParams(&response_params, target_handle, target_dir_handle); ChromeThread::PostTask( ChromeThread::IO, FROM_HERE, - NewRunnableFunction(SendMessage, sender, - new ViewMsg_DatabaseOpenFileResponse(message_id, response_params))); + NewRunnableMethod(this, + &DatabaseDispatcherHost::SendMessage, + new ViewMsg_DatabaseOpenFileResponse( + message_id, response_params))); +} + +void DatabaseDispatcherHost::OnDatabaseDeleteFile(const FilePath& vfs_file_name, + const bool& sync_dir, + int32 message_id) { + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, + &DatabaseDispatcherHost::DatabaseDeleteFile, + vfs_file_name, + sync_dir, + message_id, + kNumDeleteRetries)); } // Scheduled by the IO thread on the file thread. // Deletes the given database file, then schedules // a task on the IO thread's message loop to send an IPC back to // corresponding renderer process with the error code. -static void DatabaseDeleteFile(const DeleteFileParams& params, - int32 message_id, - int reschedule_count, - ResourceMessageFilter* sender) { - // Return an error if the file could not be deleted - // after kNumDeleteRetries times. - if (!reschedule_count) { - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableFunction(SendMessage, sender, - new ViewMsg_DatabaseDeleteFileResponse(message_id, - SQLITE_IOERR_DELETE))); - return; - } - - int error_code = - VfsBackend::DeleteFile(params.file_name, params.db_dir, params.sync_dir); - if (error_code == SQLITE_IOERR_DELETE) { - // If the file could not be deleted, try again. - MessageLoop::current()->PostDelayedTask(FROM_HERE, - NewRunnableFunction(DatabaseDeleteFile, params, message_id, - reschedule_count - 1, sender), - kDelayDeleteRetryMs); - return; +void DatabaseDispatcherHost::DatabaseDeleteFile(const FilePath& vfs_file_name, + bool sync_dir, + int32 message_id, + int reschedule_count) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + + // Return an error if the file name is invalid or if the file could not + // be deleted after kNumDeleteRetries attempts. + int error_code = SQLITE_IOERR_DELETE; + FilePath db_file_name = GetDBFileFullPath(vfs_file_name); + if (!db_file_name.empty()) { + FilePath db_dir = db_tracker_->DatabaseDirectory(); + error_code = VfsBackend::DeleteFile(db_file_name, db_dir, sync_dir); + if ((error_code == SQLITE_IOERR_DELETE) && reschedule_count) { + // If the file could not be deleted, try again. + ChromeThread::PostDelayedTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, + &DatabaseDispatcherHost::DatabaseDeleteFile, + vfs_file_name, + sync_dir, + message_id, + reschedule_count - 1), + kDelayDeleteRetryMs); + return; + } } ChromeThread::PostTask( ChromeThread::IO, FROM_HERE, - NewRunnableFunction(SendMessage, sender, - new ViewMsg_DatabaseDeleteFileResponse(message_id, error_code))); + NewRunnableMethod(this, + &DatabaseDispatcherHost::SendMessage, + new ViewMsg_DatabaseDeleteFileResponse( + message_id, error_code))); +} + +void DatabaseDispatcherHost::OnDatabaseGetFileAttributes( + const FilePath& vfs_file_name, + int32 message_id) { + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, + &DatabaseDispatcherHost::DatabaseGetFileAttributes, + vfs_file_name, + message_id)); } // Scheduled by the IO thread on the file thread. // Gets the attributes of the given database file, then schedules // a task on the IO thread's message loop to send an IPC back to // corresponding renderer process. -static void DatabaseGetFileAttributes(const FilePath& file_name, - int32 message_id, - ResourceMessageFilter* sender) { - uint32 attributes = VfsBackend::GetFileAttributes(file_name); +void DatabaseDispatcherHost::DatabaseGetFileAttributes( + const FilePath& vfs_file_name, + int32 message_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + int32 attributes = -1; + FilePath db_file_name = GetDBFileFullPath(vfs_file_name); + if (!db_file_name.empty()) + attributes = VfsBackend::GetFileAttributes(db_file_name); ChromeThread::PostTask( ChromeThread::IO, FROM_HERE, - NewRunnableFunction(SendMessage, sender, - new ViewMsg_DatabaseGetFileAttributesResponse( - message_id, attributes))); + NewRunnableMethod(this, + &DatabaseDispatcherHost::SendMessage, + new ViewMsg_DatabaseGetFileAttributesResponse( + message_id, attributes))); +} + +void DatabaseDispatcherHost::OnDatabaseGetFileSize( + const FilePath& vfs_file_name, int32 message_id) { + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, + &DatabaseDispatcherHost::DatabaseGetFileSize, + vfs_file_name, + message_id)); } // Scheduled by the IO thread on the file thread. // Gets the size of the given file, then schedules a task // on the IO thread's message loop to send an IPC back to // the corresponding renderer process. -static void DatabaseGetFileSize(const FilePath& file_name, - int32 message_id, - ResourceMessageFilter* sender) { - int64 size = VfsBackend::GetFileSize(file_name); +void DatabaseDispatcherHost::DatabaseGetFileSize(const FilePath& vfs_file_name, + int32 message_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + int64 size = 0; + FilePath db_file_name = GetDBFileFullPath(vfs_file_name); + if (!db_file_name.empty()) + size = VfsBackend::GetFileSize(db_file_name); ChromeThread::PostTask( ChromeThread::IO, FROM_HERE, - NewRunnableFunction(SendMessage, sender, - new ViewMsg_DatabaseGetFileSizeResponse(message_id, size))); -} - -} // namespace - -DatabaseDispatcherHost::DatabaseDispatcherHost( - const FilePath& profile_path, - ResourceMessageFilter* resource_message_filter) - : profile_path_(profile_path), - resource_message_filter_(resource_message_filter) { -} - -bool DatabaseDispatcherHost::OnMessageReceived( - const IPC::Message& message, bool* message_was_ok) { - *message_was_ok = true; - - bool handled = true; - IPC_BEGIN_MESSAGE_MAP_EX(DatabaseDispatcherHost, message, *message_was_ok) - IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseOpenFile, OnDatabaseOpenFile); - IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseDeleteFile, OnDatabaseDeleteFile); - IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseGetFileAttributes, - OnDatabaseGetFileAttributes); - IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseGetFileSize, - OnDatabaseGetFileSize); - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP_EX() - return handled; + NewRunnableMethod(this, + &DatabaseDispatcherHost::SendMessage, + new ViewMsg_DatabaseGetFileSizeResponse( + message_id, size))); } -FilePath DatabaseDispatcherHost::GetDBDir() { - return profile_path_.Append(FILE_PATH_LITERAL("databases")); +void DatabaseDispatcherHost::OnDatabaseOpened(const string16& origin_identifier, + const string16& database_name, + const string16& description, + int64 estimated_size) { + ChromeThread::PostTask( + ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, + &DatabaseDispatcherHost::DatabaseOpened, + origin_identifier, + database_name, + description, + estimated_size)); } -FilePath DatabaseDispatcherHost::GetDBFileFullPath(const FilePath& file_name) { - // Do not allow '\', '/' and ':' in file names. - FilePath::StringType file = file_name.value(); - if ((file.find('\\') != std::wstring::npos) || - (file.find('/') != std::wstring::npos) || - (file.find(':') != std::wstring::npos)) { - return FilePath(); - } - return GetDBDir().Append(file_name); +void DatabaseDispatcherHost::DatabaseOpened(const string16& origin_identifier, + const string16& database_name, + const string16& description, + int64 estimated_size) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + int64 database_size = 0; + int64 space_available = 0; + AddAccessedOrigin(origin_identifier); + db_tracker_->DatabaseOpened(origin_identifier, database_name, description, + estimated_size, &database_size, &space_available); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, + &DatabaseDispatcherHost::SendMessage, + new ViewMsg_DatabaseUpdateSize( + origin_identifier, database_name, + database_size, space_available))); } -void DatabaseDispatcherHost::OnDatabaseOpenFile(const FilePath& file_name, - int desired_flags, - int32 message_id) { - FilePath db_file_name = GetDBFileFullPath(file_name); - - if (db_file_name.empty()) { - ViewMsg_DatabaseOpenFileResponse_Params response_params; -#if defined(OS_WIN) - response_params.file_handle = base::kInvalidPlatformFileValue; -#elif defined(OS_POSIX) - response_params.file_handle = - base::FileDescriptor(base::kInvalidPlatformFileValue, true); - response_params.dir_handle = - base::FileDescriptor(base::kInvalidPlatformFileValue, true); -#endif - resource_message_filter_->Send(new ViewMsg_DatabaseOpenFileResponse( - message_id, response_params)); - return; - } - - OpenFileParams params; - params.db_dir = GetDBDir(); - params.file_name = db_file_name; - params.desired_flags = desired_flags; - params.handle = resource_message_filter_->handle(); - resource_message_filter_->AddRef(); +void DatabaseDispatcherHost::OnDatabaseModified( + const string16& origin_identifier, + const string16& database_name) { ChromeThread::PostTask( ChromeThread::FILE, FROM_HERE, - NewRunnableFunction( - DatabaseOpenFile, params, message_id, resource_message_filter_)); + NewRunnableMethod(this, + &DatabaseDispatcherHost::DatabaseModified, + origin_identifier, + database_name)); } -void DatabaseDispatcherHost::OnDatabaseDeleteFile( - const FilePath& file_name, const bool& sync_dir, int32 message_id) { - FilePath db_file_name = GetDBFileFullPath(file_name); - if (db_file_name.empty()) { - resource_message_filter_->Send(new ViewMsg_DatabaseDeleteFileResponse( - message_id, SQLITE_IOERR_DELETE)); +void DatabaseDispatcherHost::DatabaseModified(const string16& origin_identifier, + const string16& database_name) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + if (!HasAccessedOrigin(origin_identifier)) { + ReceivedBadMessage(ViewHostMsg_DatabaseModified::ID); return; } - DeleteFileParams params; - params.db_dir = GetDBDir(); - params.file_name = db_file_name; - params.sync_dir = sync_dir; - resource_message_filter_->AddRef(); + db_tracker_->DatabaseModified(origin_identifier, database_name); +} + +void DatabaseDispatcherHost::OnDatabaseClosed(const string16& origin_identifier, + const string16& database_name) { ChromeThread::PostTask( ChromeThread::FILE, FROM_HERE, - NewRunnableFunction( - DatabaseDeleteFile, params, message_id, kNumDeleteRetries, - resource_message_filter_)); + NewRunnableMethod(this, + &DatabaseDispatcherHost::DatabaseClosed, + origin_identifier, + database_name)); } -void DatabaseDispatcherHost::OnDatabaseGetFileAttributes( - const FilePath& file_name, int32 message_id) { - FilePath db_file_name = GetDBFileFullPath(file_name); - if (db_file_name.empty()) { - resource_message_filter_->Send( - new ViewMsg_DatabaseGetFileAttributesResponse(message_id, -1)); +void DatabaseDispatcherHost::DatabaseClosed(const string16& origin_identifier, + const string16& database_name) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + if (!HasAccessedOrigin(origin_identifier)) { + ReceivedBadMessage(ViewHostMsg_DatabaseClosed::ID); return; } - resource_message_filter_->AddRef(); - ChromeThread::PostTask( - ChromeThread::FILE, FROM_HERE, - NewRunnableFunction( - DatabaseGetFileAttributes, db_file_name, message_id, - resource_message_filter_)); + db_tracker_->DatabaseClosed(origin_identifier, database_name); } -void DatabaseDispatcherHost::OnDatabaseGetFileSize( - const FilePath& file_name, int32 message_id) { - FilePath db_file_name = GetDBFileFullPath(file_name); - if (db_file_name.empty()) { - resource_message_filter_->Send(new ViewMsg_DatabaseGetFileSizeResponse( - message_id, 0)); - return; +void DatabaseDispatcherHost::OnDatabaseSizeChanged( + const string16& origin_identifier, + const string16& database_name, + int64 database_size, + int64 space_available) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + if (HasAccessedOrigin(origin_identifier)) { + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, + &DatabaseDispatcherHost::SendMessage, + new ViewMsg_DatabaseUpdateSize( + origin_identifier, database_name, + database_size, space_available))); } +} - resource_message_filter_->AddRef(); - ChromeThread::PostTask( - ChromeThread::FILE, FROM_HERE, - NewRunnableFunction( - DatabaseGetFileSize, db_file_name, message_id, - resource_message_filter_)); +void DatabaseDispatcherHost::AddAccessedOrigin( + const string16& origin_identifier) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + accessed_origins_.insert(origin_identifier); +} + +bool DatabaseDispatcherHost::HasAccessedOrigin( + const string16& origin_identifier) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + return (accessed_origins_.find(origin_identifier) != accessed_origins_.end()); } diff --git a/chrome/browser/renderer_host/database_dispatcher_host.h b/chrome/browser/renderer_host/database_dispatcher_host.h index fd403d2..5053138 100644 --- a/chrome/browser/renderer_host/database_dispatcher_host.h +++ b/chrome/browser/renderer_host/database_dispatcher_host.h @@ -6,55 +6,105 @@ #define CHROME_BROWSER_RENDERER_HOST_DATABASE_DISPATCHER_HOST_H_ #include "base/file_path.h" +#include "base/hash_tables.h" +#include "base/process.h" +#include "base/ref_counted.h" +#include "base/string16.h" +#include "ipc/ipc_message.h" +#include "webkit/database/database_tracker.h" -class ResourceMessageFilter; - -namespace IPC { -class Message; -} - -class DatabaseDispatcherHost { +class DatabaseDispatcherHost + : public base::RefCountedThreadSafe<DatabaseDispatcherHost>, + public webkit_database::DatabaseTracker::Observer { public: - DatabaseDispatcherHost(const FilePath& profile_path, - ResourceMessageFilter* resource_message_filter); - ~DatabaseDispatcherHost() {} + DatabaseDispatcherHost(webkit_database::DatabaseTracker* db_tracker, + IPC::Message::Sender* message_sender, + base::ProcessHandle process_handle); + void Shutdown(); - // Returns true iff the message is HTML5 DB related and was processed. bool OnMessageReceived(const IPC::Message& message, bool* message_was_ok); - private: - // Message handlers. - // Processes the request to return a handle to the given DB file. - void OnDatabaseOpenFile(const FilePath& file_name, + // VFS message handlers (IO thread) + void OnDatabaseOpenFile(const FilePath& vfs_file_name, int desired_flags, int32 message_id); - - // Processes the request to delete the given DB file. - void OnDatabaseDeleteFile(const FilePath& file_name, + void OnDatabaseDeleteFile(const FilePath& vfs_file_name, const bool& sync_dir, int32 message_id); - - // Processes the request to return the attributes of the given DB file. - void OnDatabaseGetFileAttributes(const FilePath& file_name, + void OnDatabaseGetFileAttributes(const FilePath& vfs_file_name, int32 message_id); - - // Processes the request to return the size of the given file. - void OnDatabaseGetFileSize(const FilePath& file_name, + void OnDatabaseGetFileSize(const FilePath& vfs_file_name, int32 message_id); - // Returns the directory where all DB files are stored. - FilePath GetDBDir(); + // Database tracker message handlers (IO thread) + void OnDatabaseOpened(const string16& origin_identifier, + const string16& database_name, + const string16& description, + int64 estimated_size); + void OnDatabaseModified(const string16& origin_identifier, + const string16& database_name); + void OnDatabaseClosed(const string16& origin_identifier, + const string16& database_name); + + // DatabaseTracker::Observer callback (file thread) + virtual void OnDatabaseSizeChanged(const string16& origin_identifier, + const string16& database_name, + int64 database_size, + int64 space_available); + + private: + void AddObserver(); + void RemoveObserver(); + FilePath GetDBFileFullPath(const FilePath& vfs_file_name); + + void ReceivedBadMessage(uint16 msg_type); + void SendMessage(IPC::Message* message); + + // VFS message handlers (file thread) + void DatabaseOpenFile(const FilePath& vfs_file_name, + int desired_flags, + int32 message_id); + void DatabaseDeleteFile(const FilePath& vfs_file_name, + bool sync_dir, + int32 message_id, + int reschedule_count); + void DatabaseGetFileAttributes(const FilePath& vfs_file_name, + int32 message_id); + void DatabaseGetFileSize(const FilePath& vfs_file_name, + int32 message_id); + + // Database tracker message handlers (file thread) + void DatabaseOpened(const string16& origin_identifier, + const string16& file_name, + const string16& description, + int64 estimated_size); + void DatabaseModified(const string16& origin_identifier, + const string16& database_name); + void DatabaseClosed(const string16& origin_identifier, + const string16& database_name); + + void AddAccessedOrigin(const string16& origin_identifier); + bool HasAccessedOrigin(const string16& origin_identifier); + + // The database tracker for the current profile. + scoped_refptr<webkit_database::DatabaseTracker> db_tracker_; + + // The sender to be used for sending out IPC messages. + IPC::Message::Sender* message_sender_; + + // The handle of this process. + const base::ProcessHandle process_handle_; - // Returns the absolute name of the given DB file. - FilePath GetDBFileFullPath(const FilePath& file_name); + // True if and only if this instance was added as an observer + // to DatabaseTracker. + bool observer_added_; - // The user data directory. - FilePath profile_path_; + // If true, all messages that are normally processed by this class + // will be silently discarded. This field should be set to true + // only when the corresponding renderer process is about to go away. + bool shutdown_; - // The ResourceMessageFilter instance of this renderer process. Can't keep - // a refptr or else we'll get into a cycle. It's always ok to use this in - // the IO thread since if the RMF goes away, this object is deleted. - ResourceMessageFilter* resource_message_filter_; + base::hash_set<string16> accessed_origins_; }; #endif // CHROME_BROWSER_RENDERER_HOST_DATABASE_DISPATCHER_HOST_H_ diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index e386edc..2cf9b6c 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -171,7 +171,8 @@ ResourceMessageFilter::ResourceMessageFilter( new DOMStorageDispatcherHost(this, profile->GetWebKitContext(), resource_dispatcher_host->webkit_thread()))), ALLOW_THIS_IN_INITIALIZER_LIST(db_dispatcher_host_( - new DatabaseDispatcherHost(profile->GetPath(), this))), + new DatabaseDispatcherHost(profile->GetDatabaseTracker(), + this, handle()))), notification_prefs_( profile->GetDesktopNotificationService()->prefs_cache()), socket_stream_dispatcher_host_(new SocketStreamDispatcherHost), @@ -193,6 +194,9 @@ ResourceMessageFilter::~ResourceMessageFilter() { // Tell the DOM Storage dispatcher host to stop sending messages via us. dom_storage_dispatcher_host_->Shutdown(); + // Shut down the database dispatcher host. + db_dispatcher_host_->Shutdown(); + // Let interested observers know we are being deleted. NotificationService::current()->Notify( NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN, @@ -540,8 +544,7 @@ void ResourceMessageFilter::OnGetRawCookies( } void ResourceMessageFilter::OnDeleteCookie(const GURL& url, - const std::string& cookie_name) -{ + const std::string& cookie_name) { URLRequestContext* context = GetRequestContextForURL(url); net::CookieMonster* cookie_monster = context->cookie_store()-> GetCookieMonster(); diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index 9d21a4f..4971cdb 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_MSG_FILTER_H_ -#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_MSG_FILTER_H_ +#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_MESSAGE_FILTER_H_ +#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_MESSAGE_FILTER_H_ #if defined(OS_WIN) #include <windows.h> @@ -376,7 +376,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, scoped_refptr<DOMStorageDispatcherHost> dom_storage_dispatcher_host_; // Handles HTML5 DB related messages - scoped_ptr<DatabaseDispatcherHost> db_dispatcher_host_; + scoped_refptr<DatabaseDispatcherHost> db_dispatcher_host_; // A cache of notifications preferences which is used to handle // Desktop Notifications permission messages. @@ -394,4 +394,4 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, DISALLOW_COPY_AND_ASSIGN(ResourceMessageFilter); }; -#endif // CHROME_BROWSER_RENDERER_HOST_RESOURCE_MSG_FILTER_H_ +#endif // CHROME_BROWSER_RENDERER_HOST_RESOURCE_MESSAGE_FILTER_H_ diff --git a/chrome/common/db_message_filter.cc b/chrome/common/db_message_filter.cc index 3ca841b..939c6e8 100644 --- a/chrome/common/db_message_filter.cc +++ b/chrome/common/db_message_filter.cc @@ -6,6 +6,7 @@ #include "chrome/common/child_process.h" #include "chrome/common/render_messages.h" +#include "webkit/api/public/WebDatabase.h" DBMessageFilter* DBMessageFilter::instance_ = NULL; @@ -64,7 +65,16 @@ bool DBMessageFilter::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ViewMsg_DatabaseGetFileAttributesResponse, OnResponse<uint32>) IPC_MESSAGE_HANDLER(ViewMsg_DatabaseGetFileSizeResponse, OnResponse<int64>) + IPC_MESSAGE_HANDLER(ViewMsg_DatabaseUpdateSize, OnDatabaseUpdateSize) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } + +void DBMessageFilter::OnDatabaseUpdateSize(const string16& origin_identifier, + const string16& database_name, + int64 database_size, + int64 space_available) { + WebKit::WebDatabase::updateDatabaseSize( + origin_identifier, database_name, database_size, space_available); +} diff --git a/chrome/common/db_message_filter.h b/chrome/common/db_message_filter.h index 23035e9..f28ea4b 100644 --- a/chrome/common/db_message_filter.h +++ b/chrome/common/db_message_filter.h @@ -81,7 +81,7 @@ class DBMessageFilter : public IPC::ChannelProxy::MessageFilter { // and not accept any more messages. virtual void OnChannelClosing(); - // Processes the reply to a DB request. + // Processes the reply to a sync DB request. template<class ResultType> void OnResponse(int32 message_id, ResultType result) { DBMessageState *state = messages_awaiting_replies_->Lookup(message_id); @@ -92,6 +92,12 @@ class DBMessageFilter : public IPC::ChannelProxy::MessageFilter { } } + // Processes IPCs that indicate a change in the size of a DB file. + void OnDatabaseUpdateSize(const string16& origin_identifier, + const string16& database_name, + int64 database_size, + int64 space_available); + // The message loop for the IO thread. MessageLoop* io_thread_message_loop_; @@ -115,4 +121,4 @@ class DBMessageFilter : public IPC::ChannelProxy::MessageFilter { static DBMessageFilter* instance_; }; -#endif // CHROME_COMMON_DB_MESSAGE_FILTER_H_ +#endif // CHROME_COMMON_DB_MESSAGE_FILTER_H_ diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc index 86e7eab..b718773 100644 --- a/chrome/test/testing_profile.cc +++ b/chrome/test/testing_profile.cc @@ -10,6 +10,7 @@ #include "chrome/browser/history/history_backend.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/common/chrome_constants.h" +#include "webkit/database/database_tracker.h" #if defined(OS_LINUX) && !defined(TOOLKIT_VIEWS) #include "chrome/browser/gtk/gtk_theme_provider.h" @@ -182,6 +183,12 @@ void TestingProfile::UseThemeProvider(BrowserThemeProvider* theme_provider) { theme_provider_.reset(theme_provider); } +webkit_database::DatabaseTracker* TestingProfile::GetDatabaseTracker() { + if (!db_tracker_) + db_tracker_ = new webkit_database::DatabaseTracker(GetPath()); + return db_tracker_; +} + void TestingProfile::InitThemes() { if (!created_theme_provider_) { #if defined(OS_LINUX) && !defined(TOOLKIT_VIEWS) diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index 0d13268..14b64da 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -18,7 +18,6 @@ #include "chrome/browser/sessions/session_service.h" #include "chrome/common/pref_service.h" - class TestingProfile : public Profile { public: TestingProfile(); @@ -76,6 +75,7 @@ class TestingProfile : public Profile { virtual void DestroyOffTheRecordProfile() {} virtual Profile* GetOriginalProfile() { return this; } + virtual webkit_database::DatabaseTracker* GetDatabaseTracker(); virtual VisitedLinkMaster* GetVisitedLinkMaster() { return NULL; } virtual ExtensionsService* GetExtensionsService() { return NULL; } virtual UserScriptMaster* GetUserScriptMaster() { return NULL; } @@ -241,6 +241,10 @@ class TestingProfile : public Profile { // Did the last session exit cleanly? Default is true. bool last_session_exited_cleanly_; + + // The main database tracker for this profile. + // Should be used only on the file thread. + scoped_refptr<webkit_database::DatabaseTracker> db_tracker_; }; // A profile that derives from another profile. This does not actually @@ -248,8 +252,8 @@ class TestingProfile : public Profile { // site information. class DerivedTestingProfile : public TestingProfile { public: - DerivedTestingProfile(Profile* profile) : original_profile_(profile) { - } + explicit DerivedTestingProfile(Profile* profile) + : original_profile_(profile) {} virtual ProfileId GetRuntimeId() { return original_profile_->GetRuntimeId(); |