From 81be9bdbe8e380ea383c3ff0e3ef496524793fec Mon Sep 17 00:00:00 2001
From: "jochen@chromium.org"
 <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Wed, 31 Mar 2010 07:36:24 +0000
Subject: Block database access on allowDatabase instead of databaseOpenFile.

BUG=36435
TEST=Set cookie settings to ASK and open a page with web databases.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43183 0039d316-1c4b-4281-b951-d872f2087c98
---
 chrome/browser/cookie_modal_dialog.cc              |   4 +
 chrome/browser/cookie_modal_dialog.h               |   6 +
 chrome/browser/cookie_modal_dialog_gtk.cc          |   4 +-
 chrome/browser/gtk/gtk_chrome_cookie_view.cc       |  23 ++-
 chrome/browser/gtk/gtk_chrome_cookie_view.h        |   6 +-
 chrome/browser/message_box_handler.cc              |   5 +-
 chrome/browser/message_box_handler.h               |   2 +
 .../renderer_host/database_dispatcher_host.cc      | 200 ++++++++-------------
 .../renderer_host/database_dispatcher_host.h       |  21 ++-
 .../renderer_host/database_permission_request.cc   |   7 +-
 .../renderer_host/database_permission_request.h    |   6 +
 chrome/browser/views/cookie_prompt_view.cc         |   4 +-
 chrome/browser/views/database_open_info_view.cc    | 108 +++--------
 chrome/browser/views/database_open_info_view.h     |  32 +---
 chrome/common/render_messages_internal.h           |   9 +
 chrome/renderer/render_thread.cc                   |   1 +
 chrome/renderer/render_view.cc                     |  15 ++
 chrome/renderer/render_view.h                      |   3 +
 18 files changed, 202 insertions(+), 254 deletions(-)

(limited to 'chrome')

diff --git a/chrome/browser/cookie_modal_dialog.cc b/chrome/browser/cookie_modal_dialog.cc
index 45347dc..4435bcb 100644
--- a/chrome/browser/cookie_modal_dialog.cc
+++ b/chrome/browser/cookie_modal_dialog.cc
@@ -50,12 +50,16 @@ CookiePromptModalDialog::CookiePromptModalDialog(
     HostContentSettingsMap* host_content_settings_map,
     const GURL& origin,
     const string16& database_name,
+    const string16& display_name,
+    unsigned long estimated_size,
     CookiePromptModalDialogDelegate* delegate)
     : AppModalDialog(tab_contents, std::wstring()),
       host_content_settings_map_(host_content_settings_map),
       dialog_type_(DIALOG_TYPE_DATABASE),
       origin_(origin),
       database_name_(database_name),
+      display_name_(display_name),
+      estimated_size_(estimated_size),
       delegate_(delegate) {
 }
 
diff --git a/chrome/browser/cookie_modal_dialog.h b/chrome/browser/cookie_modal_dialog.h
index 793c587..bfc2b67 100644
--- a/chrome/browser/cookie_modal_dialog.h
+++ b/chrome/browser/cookie_modal_dialog.h
@@ -52,6 +52,8 @@ class CookiePromptModalDialog : public AppModalDialog {
                           HostContentSettingsMap* host_content_settings_map,
                           const GURL& origin,
                           const string16& database_name,
+                          const string16& display_name,
+                          unsigned long estimated_size,
                           CookiePromptModalDialogDelegate* delegate);
   CookiePromptModalDialog(TabContents* tab_contents,
                           HostContentSettingsMap* host_content_settings_map,
@@ -80,6 +82,8 @@ class CookiePromptModalDialog : public AppModalDialog {
   const string16& local_storage_key() const { return local_storage_key_; }
   const string16& local_storage_value() const { return local_storage_value_; }
   const string16& database_name() const { return database_name_; }
+  const string16& display_name() const { return display_name_; }
+  unsigned long estimated_size() const { return estimated_size_; }
   const GURL& appcache_manifest_url() const { return appcache_manifest_url_; }
   TabContents* tab_contents() const { return tab_contents_; }
 
@@ -114,6 +118,8 @@ class CookiePromptModalDialog : public AppModalDialog {
   const string16 local_storage_key_;
   const string16 local_storage_value_;
   const string16 database_name_;
+  const string16 display_name_;
+  unsigned long estimated_size_;
   const GURL appcache_manifest_url_;
 
   // The caller should provide a delegate in order to receive results
diff --git a/chrome/browser/cookie_modal_dialog_gtk.cc b/chrome/browser/cookie_modal_dialog_gtk.cc
index 700236a..c7d7f16 100644
--- a/chrome/browser/cookie_modal_dialog_gtk.cc
+++ b/chrome/browser/cookie_modal_dialog_gtk.cc
@@ -118,7 +118,9 @@ NativeDialog CookiePromptModalDialog::CreateNativeDialog() {
     gtk_chrome_cookie_view_display_database_accessed(
         cookie_view,
         origin().host(),
-        database_name());
+        database_name(),
+        display_name(),
+        estimated_size());
   } else if (type == CookiePromptModalDialog::DIALOG_TYPE_APPCACHE) {
     gtk_chrome_cookie_view_display_appcache_created(
         cookie_view,
diff --git a/chrome/browser/gtk/gtk_chrome_cookie_view.cc b/chrome/browser/gtk/gtk_chrome_cookie_view.cc
index 94bb9c1..57f7737 100644
--- a/chrome/browser/gtk/gtk_chrome_cookie_view.cc
+++ b/chrome/browser/gtk/gtk_chrome_cookie_view.cc
@@ -101,6 +101,10 @@ void InitStyles(GtkChromeCookieView *self) {
                          dialog_style);
   InitBrowserDetailStyle(self->database_accessed_name_entry_, label_style,
                          dialog_style);
+  InitBrowserDetailStyle(self->database_accessed_description_entry_,
+                         label_style, dialog_style);
+  InitBrowserDetailStyle(self->database_accessed_size_entry_, label_style,
+                         dialog_style);
 
   // AppCache created item.
   InitBrowserDetailStyle(self->appcache_created_manifest_entry_, label_style,
@@ -152,6 +156,8 @@ void SetDatabaseAccessedSensitivity(GtkChromeCookieView* self,
                                     gboolean enabled) {
   gtk_widget_set_sensitive(self->database_accessed_origin_entry_, enabled);
   gtk_widget_set_sensitive(self->database_accessed_name_entry_, enabled);
+  gtk_widget_set_sensitive(self->database_accessed_description_entry_, enabled);
+  gtk_widget_set_sensitive(self->database_accessed_size_entry_, enabled);
 }
 
 void SetAppCacheCreatedSensitivity(GtkChromeCookieView* self,
@@ -333,6 +339,12 @@ static void gtk_chrome_cookie_view_init(GtkChromeCookieView *self) {
   InitDetailRow(row++, IDS_COOKIES_WEB_DATABASE_NAME,
                 self->database_accessed_table_,
                 &self->database_accessed_name_entry_);
+  InitDetailRow(row++, IDS_COOKIES_WEB_DATABASE_DESCRIPTION_LABEL,
+                self->database_accessed_table_,
+                &self->database_accessed_description_entry_);
+  InitDetailRow(row++, IDS_COOKIES_SIZE_LABEL,
+                self->database_accessed_table_,
+                &self->database_accessed_size_entry_);
 
   // AppCache created prompt.
   self->appcache_created_table_ = gtk_table_new(1, 2, FALSE);
@@ -495,13 +507,22 @@ void gtk_chrome_cookie_view_display_local_storage_item(
 void gtk_chrome_cookie_view_display_database_accessed(
     GtkChromeCookieView* self,
     const std::string& host,
-    const string16& database_name) {
+    const string16& database_name,
+    const string16& display_name,
+    unsigned long estimated_size) {
   UpdateVisibleDetailedInfo(self, self->database_accessed_table_);
 
   gtk_entry_set_text(GTK_ENTRY(self->database_accessed_origin_entry_),
                      host.c_str());
   gtk_entry_set_text(GTK_ENTRY(self->database_accessed_name_entry_),
                      UTF16ToUTF8(database_name).c_str());
+  gtk_entry_set_text(GTK_ENTRY(self->database_accessed_description_entry_),
+                     UTF16ToUTF8(display_name).c_str());
+  gtk_entry_set_text(GTK_ENTRY(self->database_accessed_size_entry_),
+                     WideToUTF8(FormatBytes(
+                         estimated_size,
+                         GetByteDisplayUnits(estimated_size),
+                         true)).c_str());
   SetDatabaseAccessedSensitivity(self, TRUE);
 }
 
diff --git a/chrome/browser/gtk/gtk_chrome_cookie_view.h b/chrome/browser/gtk/gtk_chrome_cookie_view.h
index 73706f3..e729b04 100644
--- a/chrome/browser/gtk/gtk_chrome_cookie_view.h
+++ b/chrome/browser/gtk/gtk_chrome_cookie_view.h
@@ -95,6 +95,8 @@ typedef struct {
   GtkWidget* database_accessed_table_;
   GtkWidget* database_accessed_origin_entry_;
   GtkWidget* database_accessed_name_entry_;
+  GtkWidget* database_accessed_description_entry_;
+  GtkWidget* database_accessed_size_entry_;
 
   // The appcache created widgets.
   GtkWidget* appcache_created_table_;
@@ -157,7 +159,9 @@ void gtk_chrome_cookie_view_display_local_storage_item(
 void gtk_chrome_cookie_view_display_database_accessed(
     GtkChromeCookieView* self,
     const std::string& host,
-    const string16& database_name);
+    const string16& database_name,
+    const string16& display_name,
+    unsigned long estimated_size);
 
 void gtk_chrome_cookie_view_display_appcache_created(
     GtkChromeCookieView* self,
diff --git a/chrome/browser/message_box_handler.cc b/chrome/browser/message_box_handler.cc
index e004a0e..1350c5c 100644
--- a/chrome/browser/message_box_handler.cc
+++ b/chrome/browser/message_box_handler.cc
@@ -70,10 +70,13 @@ void RunDatabasePrompt(
     HostContentSettingsMap* host_content_settings_map,
     const GURL& origin,
     const string16& database_name,
+    const string16& display_name,
+    unsigned long estimated_size,
     CookiePromptModalDialogDelegate* delegate) {
   Singleton<AppModalDialogQueue>()->AddDialog(
       new CookiePromptModalDialog(tab_contents, host_content_settings_map,
-                                  origin, database_name, delegate));
+                                  origin, database_name, display_name,
+                                  estimated_size, delegate));
 }
 
 void RunAppCachePrompt(
diff --git a/chrome/browser/message_box_handler.h b/chrome/browser/message_box_handler.h
index be821f7..7a66902 100644
--- a/chrome/browser/message_box_handler.h
+++ b/chrome/browser/message_box_handler.h
@@ -69,6 +69,8 @@ void RunDatabasePrompt(
     HostContentSettingsMap* host_content_settings_map,
     const GURL& origin,
     const string16& database_name,
+    const string16& display_name,
+    unsigned long estimated_size,
     CookiePromptModalDialogDelegate* delegate);
 
 // This will display a modal dialog box with the |manifest_url| and ask the
diff --git a/chrome/browser/renderer_host/database_dispatcher_host.cc b/chrome/browser/renderer_host/database_dispatcher_host.cc
index e7734ac..4c56f3b 100644
--- a/chrome/browser/renderer_host/database_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/database_dispatcher_host.cc
@@ -97,6 +97,7 @@ bool DatabaseDispatcherHost::OnMessageReceived(
     IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseOpened, OnDatabaseOpened)
     IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseModified, OnDatabaseModified)
     IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseClosed, OnDatabaseClosed)
+    IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_AllowDatabase, OnAllowDatabase)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP_EX()
   return handled;
@@ -107,11 +108,18 @@ void DatabaseDispatcherHost::ReceivedBadMessage(uint32 msg_type) {
       msg_type, process_handle_);
 }
 
-// Scheduled by the file thread on the IO thread.
-// Sends back to the renderer process the given message.
-void DatabaseDispatcherHost::SendMessage(IPC::Message* message) {
-  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
-  if (!shutdown_)
+void DatabaseDispatcherHost::Send(IPC::Message* message) {
+  if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+    if (!ChromeThread::PostTask(
+            ChromeThread::IO, FROM_HERE,
+            NewRunnableMethod(this,
+                              &DatabaseDispatcherHost::Send,
+                              message)))
+      delete message;
+    return;
+  }
+
+  if (!shutdown_ && resource_message_filter_)
     resource_message_filter_->Send(message);
   else
     delete message;
@@ -127,55 +135,13 @@ void DatabaseDispatcherHost::OnDatabaseOpenFile(const string16& vfs_file_name,
         NewRunnableMethod(this, &DatabaseDispatcherHost::AddObserver));
   }
 
-  // Only ask permission on the main database file in read/write mode.
-  if (!VfsBackend::FileTypeIsMainDB(desired_flags) ||
-      !VfsBackend::OpenTypeIsReadWrite(desired_flags)) {
-    OnDatabaseOpenFileAllowed(vfs_file_name, desired_flags, message_id);
-    return;
-  }
-
-  string16 origin_identifier;
-  string16 database_name;
-  bool ok = DatabaseUtil::CrackVfsFileName(vfs_file_name,
-                                           &origin_identifier,
-                                           &database_name,
-                                           NULL);
-  DCHECK(ok);  // Should we assume this is an attack and kill the renderer?
-  if (!ok) {
-    OnDatabaseOpenFileBlocked(message_id);
-    return;
-  }
-
-  // TODO(jorlow): createFromDatabaseIdentifier should not return a pointer.
-  scoped_ptr<WebSecurityOrigin> security_origin(
-      WebSecurityOrigin::createFromDatabaseIdentifier(origin_identifier));
-  string16 origin(security_origin->toString());
-  GURL url = GURL(origin);
-
-  HostContentSettingsMap* host_content_settings_map = resource_message_filter_->
-      GetRequestContextForURL(url)->host_content_settings_map();
-  ContentSetting content_setting = host_content_settings_map->GetContentSetting(
-      url.host(), CONTENT_SETTINGS_TYPE_COOKIES);
-
-  if (content_setting == CONTENT_SETTING_ASK) {
-    // Create a task for each possible outcome.
-    scoped_ptr<Task> on_allow(NewRunnableMethod(
-        this, &DatabaseDispatcherHost::OnDatabaseOpenFileAllowed,
-        vfs_file_name, desired_flags, message_id));
-    scoped_ptr<Task> on_block(NewRunnableMethod(
-        this, &DatabaseDispatcherHost::OnDatabaseOpenFileBlocked, message_id));
-    // And then let the permission request object do the rest.
-    scoped_refptr<DatabasePermissionRequest> request(
-        new DatabasePermissionRequest(url, database_name, on_allow.release(),
-                                      on_block.release(),
-                                      host_content_settings_map));
-    request->RequestPermission();
-  } else if (content_setting == CONTENT_SETTING_ALLOW) {
-    OnDatabaseOpenFileAllowed(vfs_file_name, desired_flags, message_id);
-  } else {
-    DCHECK(content_setting == CONTENT_SETTING_BLOCK);
-    OnDatabaseOpenFileBlocked(message_id);
-  }
+  ChromeThread::PostTask(
+      ChromeThread::FILE, FROM_HERE,
+      NewRunnableMethod(this,
+                        &DatabaseDispatcherHost::DatabaseOpenFile,
+                        vfs_file_name,
+                        desired_flags,
+                        message_id));
 }
 
 static void SetOpenFileResponseParams(
@@ -220,12 +186,7 @@ void DatabaseDispatcherHost::DatabaseOpenFile(const string16& vfs_file_name,
 
   ViewMsg_DatabaseOpenFileResponse_Params response_params;
   SetOpenFileResponseParams(&response_params, target_handle, target_dir_handle);
-  ChromeThread::PostTask(
-      ChromeThread::IO, FROM_HERE,
-      NewRunnableMethod(this,
-                        &DatabaseDispatcherHost::SendMessage,
-                        new ViewMsg_DatabaseOpenFileResponse(
-                            message_id, response_params)));
+  Send(new ViewMsg_DatabaseOpenFileResponse(message_id, response_params));
 }
 
 void DatabaseDispatcherHost::OnDatabaseDeleteFile(const string16& vfs_file_name,
@@ -273,12 +234,7 @@ void DatabaseDispatcherHost::DatabaseDeleteFile(const string16& vfs_file_name,
     }
   }
 
-  ChromeThread::PostTask(
-      ChromeThread::IO, FROM_HERE,
-      NewRunnableMethod(this,
-                        &DatabaseDispatcherHost::SendMessage,
-                        new ViewMsg_DatabaseDeleteFileResponse(
-                            message_id, error_code)));
+  Send(new ViewMsg_DatabaseDeleteFileResponse(message_id, error_code));
 }
 
 void DatabaseDispatcherHost::OnDatabaseGetFileAttributes(
@@ -305,12 +261,7 @@ void DatabaseDispatcherHost::DatabaseGetFileAttributes(
       DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
   if (!db_file.empty())
     attributes = VfsBackend::GetFileAttributes(db_file);
-  ChromeThread::PostTask(
-      ChromeThread::IO, FROM_HERE,
-      NewRunnableMethod(this,
-                        &DatabaseDispatcherHost::SendMessage,
-                        new ViewMsg_DatabaseGetFileAttributesResponse(
-                            message_id, attributes)));
+  Send(new ViewMsg_DatabaseGetFileAttributesResponse(message_id, attributes));
 }
 
 void DatabaseDispatcherHost::OnDatabaseGetFileSize(
@@ -335,12 +286,7 @@ void DatabaseDispatcherHost::DatabaseGetFileSize(const string16& vfs_file_name,
       DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
   if (!db_file.empty())
     size = VfsBackend::GetFileSize(db_file);
-  ChromeThread::PostTask(
-      ChromeThread::IO, FROM_HERE,
-      NewRunnableMethod(this,
-                        &DatabaseDispatcherHost::SendMessage,
-                        new ViewMsg_DatabaseGetFileSizeResponse(
-                            message_id, size)));
+  Send(new ViewMsg_DatabaseGetFileSizeResponse(message_id, size));
 }
 
 void DatabaseDispatcherHost::OnDatabaseOpened(const string16& origin_identifier,
@@ -367,13 +313,8 @@ void DatabaseDispatcherHost::DatabaseOpened(const string16& origin_identifier,
   database_connections_.AddConnection(origin_identifier, database_name);
   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)));
+  Send(new ViewMsg_DatabaseUpdateSize(origin_identifier, database_name,
+                                      database_size, space_available));
 }
 
 void DatabaseDispatcherHost::OnDatabaseModified(
@@ -409,6 +350,49 @@ void DatabaseDispatcherHost::OnDatabaseClosed(const string16& origin_identifier,
                         database_name));
 }
 
+void DatabaseDispatcherHost::OnAllowDatabase(const std::string& origin_url,
+                                             const string16& name,
+                                             const string16& display_name,
+                                             unsigned long estimated_size,
+                                             IPC::Message* reply_msg) {
+  GURL url = GURL(origin_url);
+  HostContentSettingsMap* host_content_settings_map = resource_message_filter_->
+      GetRequestContextForURL(url)->host_content_settings_map();
+  ContentSetting content_setting = host_content_settings_map->GetContentSetting(
+      url.host(), CONTENT_SETTINGS_TYPE_COOKIES);
+
+  if (content_setting == CONTENT_SETTING_ASK) {
+    // Create a task for each possible outcome.
+    scoped_ptr<Task> on_allow(NewRunnableMethod(
+        this, &DatabaseDispatcherHost::AllowDatabaseResponse,
+        reply_msg, CONTENT_SETTING_ALLOW));
+    scoped_ptr<Task> on_block(NewRunnableMethod(
+        this, &DatabaseDispatcherHost::AllowDatabaseResponse,
+        reply_msg, CONTENT_SETTING_BLOCK));
+    // And then let the permission request object do the rest.
+    scoped_refptr<DatabasePermissionRequest> request(
+        new DatabasePermissionRequest(url, name, display_name, estimated_size,
+                                      on_allow.release(), on_block.release(),
+                                      host_content_settings_map));
+    request->RequestPermission();
+
+    // Tell the renderer that it needs to run a nested message loop.
+    Send(new ViewMsg_SignalCookiePromptEvent());
+    return;
+  }
+
+  AllowDatabaseResponse(reply_msg, content_setting);
+}
+
+void DatabaseDispatcherHost::AllowDatabaseResponse(
+    IPC::Message* reply_msg, ContentSetting content_setting) {
+  DCHECK((content_setting == CONTENT_SETTING_ALLOW) ||
+         (content_setting == CONTENT_SETTING_BLOCK));
+  ViewHostMsg_AllowDatabase::WriteReplyParams(
+      reply_msg, content_setting == CONTENT_SETTING_ALLOW);
+  Send(reply_msg);
+}
+
 void DatabaseDispatcherHost::DatabaseClosed(const string16& origin_identifier,
                                             const string16& database_name) {
   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
@@ -429,13 +413,8 @@ void DatabaseDispatcherHost::OnDatabaseSizeChanged(
     int64 space_available) {
   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
   if (database_connections_.IsOriginUsed(origin_identifier)) {
-    ChromeThread::PostTask(
-        ChromeThread::IO, FROM_HERE,
-        NewRunnableMethod(this,
-                          &DatabaseDispatcherHost::SendMessage,
-                          new ViewMsg_DatabaseUpdateSize(
-                              origin_identifier, database_name,
-                              database_size, space_available)));
+    Send(new ViewMsg_DatabaseUpdateSize(origin_identifier, database_name,
+                                        database_size, space_available));
   }
 }
 
@@ -443,40 +422,5 @@ void DatabaseDispatcherHost::OnDatabaseScheduledForDeletion(
     const string16& origin_identifier,
     const string16& database_name) {
   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
-  ChromeThread::PostTask(
-      ChromeThread::IO, FROM_HERE,
-      NewRunnableMethod(this,
-                        &DatabaseDispatcherHost::SendMessage,
-                        new ViewMsg_DatabaseCloseImmediately(
-                            origin_identifier, database_name)));
-}
-
-void DatabaseDispatcherHost::OnDatabaseOpenFileAllowed(
-    const string16& vfs_file_name, int desired_flags, int32 message_id) {
-  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
-  if (shutdown_)
-    return;
-
-  ChromeThread::PostTask(
-      ChromeThread::FILE, FROM_HERE,
-      NewRunnableMethod(this,
-                        &DatabaseDispatcherHost::DatabaseOpenFile,
-                        vfs_file_name,
-                        desired_flags,
-                        message_id));
-}
-
-void DatabaseDispatcherHost::OnDatabaseOpenFileBlocked(int32 message_id) {
-  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
-  if (shutdown_)
-    return;
-
-  // This will result in failed transactions NOT a failed window.openDatabase
-  // call.
-  ViewMsg_DatabaseOpenFileResponse_Params response_params;
-  SetOpenFileResponseParams(&response_params,
-                            base::kInvalidPlatformFileValue,
-                            base::kInvalidPlatformFileValue);
-  SendMessage(new ViewMsg_DatabaseOpenFileResponse(message_id,
-                                                   response_params));
+  Send(new ViewMsg_DatabaseCloseImmediately(origin_identifier, database_name));
 }
diff --git a/chrome/browser/renderer_host/database_dispatcher_host.h b/chrome/browser/renderer_host/database_dispatcher_host.h
index 4c16d06..251bc5b 100644
--- a/chrome/browser/renderer_host/database_dispatcher_host.h
+++ b/chrome/browser/renderer_host/database_dispatcher_host.h
@@ -14,6 +14,9 @@
 #include "webkit/database/database_connections.h"
 #include "webkit/database/database_tracker.h"
 
+class GURL;
+class HostContentSettingsMap;
+class Receiver;
 class ResourceMessageFilter;
 
 class DatabaseDispatcherHost
@@ -48,6 +51,11 @@ class DatabaseDispatcherHost
                           const string16& database_name);
   void OnDatabaseClosed(const string16& origin_identifier,
                         const string16& database_name);
+  void OnAllowDatabase(const std::string& origin_url,
+                       const string16& name,
+                       const string16& display_name,
+                       unsigned long estimated_size,
+                       IPC::Message* reply_msg);
 
   // DatabaseTracker::Observer callbacks (file thread)
   virtual void OnDatabaseSizeChanged(const string16& origin_identifier,
@@ -57,12 +65,15 @@ class DatabaseDispatcherHost
   virtual void OnDatabaseScheduledForDeletion(const string16& origin_identifier,
                                               const string16& database_name);
 
+  void Send(IPC::Message* message);
+
  private:
+  class PromptDelegate;
+
   void AddObserver();
   void RemoveObserver();
 
   void ReceivedBadMessage(uint32 msg_type);
-  void SendMessage(IPC::Message* message);
 
   // VFS message handlers (file thread)
   void DatabaseOpenFile(const string16& vfs_file_name,
@@ -87,11 +98,9 @@ class DatabaseDispatcherHost
   void DatabaseClosed(const string16& origin_identifier,
                       const string16& database_name);
 
-  // Called once we decide whether to allow or block an open file request.
-  void OnDatabaseOpenFileAllowed(const string16& vfs_file_name,
-                                 int desired_flags,
-                                 int32 message_id);
-  void OnDatabaseOpenFileBlocked(int32 message_id);
+  // CookiePromptModalDialog response handler (io thread)
+  void AllowDatabaseResponse(IPC::Message* reply_msg,
+                             ContentSetting content_setting);
 
   // The database tracker for the current profile.
   scoped_refptr<webkit_database::DatabaseTracker> db_tracker_;
diff --git a/chrome/browser/renderer_host/database_permission_request.cc b/chrome/browser/renderer_host/database_permission_request.cc
index 5efb567..fb417e7 100644
--- a/chrome/browser/renderer_host/database_permission_request.cc
+++ b/chrome/browser/renderer_host/database_permission_request.cc
@@ -13,11 +13,15 @@
 DatabasePermissionRequest::DatabasePermissionRequest(
     const GURL& url,
     const string16& database_name,
+    const string16& display_name,
+    unsigned long estimated_size,
     Task* on_allow,
     Task* on_block,
     HostContentSettingsMap* settings_map)
     : url_(url),
       database_name_(database_name),
+      display_name_(display_name),
+      estimated_size_(estimated_size),
       on_allow_(on_allow),
       on_block_(on_block),
       host_content_settings_map_(settings_map) {
@@ -55,7 +59,8 @@ void DatabasePermissionRequest::RequestPermission() {
   // Will call either AllowSiteData or BlockSiteData which will NULL out our
   // self reference.
   RunDatabasePrompt(browser->GetSelectedTabContents(),
-                    host_content_settings_map_, url_, database_name_, this);
+                    host_content_settings_map_, url_, database_name_,
+                    display_name_, estimated_size_, this);
 }
 
 void DatabasePermissionRequest::AllowSiteData(bool session_expire) {
diff --git a/chrome/browser/renderer_host/database_permission_request.h b/chrome/browser/renderer_host/database_permission_request.h
index 8b3f033..7ad09b5e 100644
--- a/chrome/browser/renderer_host/database_permission_request.h
+++ b/chrome/browser/renderer_host/database_permission_request.h
@@ -22,6 +22,8 @@ class DatabasePermissionRequest
  public:
   DatabasePermissionRequest(const GURL& url,
                             const string16& database_name,
+                            const string16& display_name,
+                            unsigned long estimated_size,
                             Task* on_allow,
                             Task* on_block,
                             HostContentSettingsMap* settings_map);
@@ -29,6 +31,8 @@ class DatabasePermissionRequest
 
   const GURL& url() const { return url_; }
   const string16& database_name() const { return database_name_; }
+  const string16& display_name() const { return display_name_; }
+  unsigned long estimated_size() const { return estimated_size_; }
 
   // Start the permission request process.
   void RequestPermission();
@@ -43,6 +47,8 @@ class DatabasePermissionRequest
   // The URL to get permission for.
   const GURL url_;
   const string16 database_name_;
+  const string16 display_name_;
+  unsigned long estimated_size_;
 
   // Set on IO, possibly release()ed on UI, destroyed on IO or UI.
   scoped_ptr<Task> on_allow_;
diff --git a/chrome/browser/views/cookie_prompt_view.cc b/chrome/browser/views/cookie_prompt_view.cc
index f89724ad..b2b2a5f 100644
--- a/chrome/browser/views/cookie_prompt_view.cc
+++ b/chrome/browser/views/cookie_prompt_view.cc
@@ -240,7 +240,9 @@ void CookiePromptView::Init() {
     DatabaseOpenInfoView* view = new DatabaseOpenInfoView();
     layout->AddView(view, 1, 1, GridLayout::FILL, GridLayout::CENTER);
     view->SetFields(parent_->origin().host(),
-                    parent_->database_name());
+                    parent_->database_name(),
+                    parent_->display_name(),
+                    parent_->estimated_size());
     info_view_ = view;
   } else if (type == CookiePromptModalDialog::DIALOG_TYPE_APPCACHE) {
     static const int kAppCacheInfoLabels[] = {
diff --git a/chrome/browser/views/database_open_info_view.cc b/chrome/browser/views/database_open_info_view.cc
index a670776..1e0fbc2 100644
--- a/chrome/browser/views/database_open_info_view.cc
+++ b/chrome/browser/views/database_open_info_view.cc
@@ -4,103 +4,37 @@
 
 #include "chrome/browser/views/database_open_info_view.h"
 
-#include <algorithm>
-
 #include "app/l10n_util.h"
-#include "base/i18n/time_formatting.h"
 #include "base/utf_string_conversions.h"
-#include "gfx/color_utils.h"
 #include "grit/generated_resources.h"
-#include "views/grid_layout.h"
-#include "views/controls/label.h"
-#include "views/controls/textfield/textfield.h"
-#include "views/standard_layout.h"
 
-static const int kDatabaseOpenInfoViewBorderSize = 1;
-static const int kDatabaseOpenInfoViewInsetSize = 3;
+namespace {
+const int kInfoLabelIds[] = {
+    IDS_COOKIES_COOKIE_DOMAIN_LABEL,
+    IDS_COOKIES_WEB_DATABASE_NAME,
+    IDS_COOKIES_WEB_DATABASE_DESCRIPTION_LABEL,
+    IDS_COOKIES_SIZE_LABEL
+};
+}  // namespace
 
 ///////////////////////////////////////////////////////////////////////////////
 // DatabaseOpenInfoView, public:
 
 DatabaseOpenInfoView::DatabaseOpenInfoView()
-    : host_value_field_(NULL),
-      database_name_value_field_(NULL) {
-}
-
-DatabaseOpenInfoView::~DatabaseOpenInfoView() {
+    : GenericInfoView(ARRAYSIZE(kInfoLabelIds), kInfoLabelIds) {
 }
 
 void DatabaseOpenInfoView::SetFields(const std::string& host,
-                                     const string16& database_name) {
-  host_value_field_->SetText(UTF8ToWide(host));
-  database_name_value_field_->SetText(database_name);
-  EnableDisplay(true);
-}
-
-void DatabaseOpenInfoView::EnableDisplay(bool enabled) {
-  host_value_field_->SetEnabled(enabled);
-  database_name_value_field_->SetEnabled(enabled);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// DatabaseOpenInfoView, views::View overrides:
-
-void DatabaseOpenInfoView::ViewHierarchyChanged(bool is_add,
-                                                views::View* parent,
-                                                views::View* child) {
-  if (is_add && child == this)
-    Init();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// DatabaseOpenInfoView, private:
-
-void DatabaseOpenInfoView::Init() {
-  SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW);
-  views::Border* border = views::Border::CreateSolidBorder(
-      kDatabaseOpenInfoViewBorderSize, border_color);
-  set_border(border);
-
-  views::Label* host_label = new views::Label(
-      l10n_util::GetString(IDS_COOKIES_COOKIE_DOMAIN_LABEL));
-  host_value_field_ = new views::Textfield;
-  views::Label* database_name_label = new views::Label(
-      l10n_util::GetString(IDS_COOKIES_WEB_DATABASE_NAME));
-  database_name_value_field_ = new views::Textfield;
-
-  using views::GridLayout;
-
-  GridLayout* layout = new GridLayout(this);
-  layout->SetInsets(kDatabaseOpenInfoViewInsetSize,
-                    kDatabaseOpenInfoViewInsetSize,
-                    kDatabaseOpenInfoViewInsetSize,
-                    kDatabaseOpenInfoViewInsetSize);
-  SetLayoutManager(layout);
-
-  int three_column_layout_id = 0;
-  views::ColumnSet* column_set = layout->AddColumnSet(three_column_layout_id);
-  column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
-                        GridLayout::USE_PREF, 0, 0);
-  column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
-  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
-                        GridLayout::USE_PREF, 0, 0);
-
-  layout->StartRow(0, three_column_layout_id);
-  layout->AddView(host_label);
-  layout->AddView(host_value_field_);
-  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
-  layout->StartRow(0, three_column_layout_id);
-  layout->AddView(database_name_label);
-  layout->AddView(database_name_value_field_);
-
-  // Color these borderless text areas the same as the containing dialog.
-  SkColor text_area_background = color_utils::GetSysSkColor(COLOR_3DFACE);
-  // Now that the Textfields are in the view hierarchy, we can initialize them.
-  host_value_field_->SetReadOnly(true);
-  host_value_field_->RemoveBorder();
-  host_value_field_->SetBackgroundColor(text_area_background);
-  database_name_value_field_->SetReadOnly(true);
-  database_name_value_field_->RemoveBorder();
-  database_name_value_field_->SetBackgroundColor(text_area_background);
+                                     const string16& database_name,
+                                     const string16& display_name,
+                                     unsigned long estimated_size) {
+  string16 url = UTF8ToUTF16(host);
+  string16 size = FormatBytes(estimated_size,
+                              GetByteDisplayUnits(estimated_size),
+                              true);
+  int row = 0;
+  SetValue(row++, url);
+  SetValue(row++, database_name);
+  SetValue(row++, display_name);
+  SetValue(row++, size);
 }
-
diff --git a/chrome/browser/views/database_open_info_view.h b/chrome/browser/views/database_open_info_view.h
index 84954f5..63d24e2 100644
--- a/chrome/browser/views/database_open_info_view.h
+++ b/chrome/browser/views/database_open_info_view.h
@@ -5,47 +5,25 @@
 #ifndef CHROME_BROWSER_VIEWS_DATABASE_OPEN_INFO_VIEW_H_
 #define CHROME_BROWSER_VIEWS_DATABASE_OPEN_INFO_VIEW_H_
 
-#include <string>
-#include <vector>
-
 #include "base/string16.h"
-#include "views/view.h"
-
-namespace views {
-class Label;
-class Textfield;
-}
+#include "chrome/browser/views/generic_info_view.h"
 
 ///////////////////////////////////////////////////////////////////////////////
 // DatabaseOpenInfoView
 //
 //  Responsible for displaying a tabular grid of Database information when
 //  prompting for permission to open a new database.
-class DatabaseOpenInfoView : public views::View {
+class DatabaseOpenInfoView : public GenericInfoView {
  public:
   DatabaseOpenInfoView();
-  virtual ~DatabaseOpenInfoView();
 
   // Update the display from the specified Database data.
   void SetFields(const std::string& host,
-                 const string16& database_name);
-
-  // Enables or disables the local storate property text fields.
-  void EnableDisplay(bool enabled);
-
- protected:
-  // views::View overrides:
-  virtual void ViewHierarchyChanged(
-      bool is_add, views::View* parent, views::View* child);
+                 const string16& database_name,
+                 const string16& display_name,
+                 unsigned long estimated_size);
 
  private:
-  // Set up the view layout
-  void Init();
-
-  // Individual property labels
-  views::Textfield* host_value_field_;
-  views::Textfield* database_name_value_field_;
-
   DISALLOW_COPY_AND_ASSIGN(DatabaseOpenInfoView);
 };
 
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 41c8f4d..67fc00f 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -2115,6 +2115,15 @@ IPC_BEGIN_MESSAGES(ViewHost)
   // ViewMsg_CSSInsertRequest message and css has been inserted into the frame.
   IPC_MESSAGE_ROUTED0(ViewHostMsg_OnCSSInserted)
 
+  // Sent by the renderer process to check whether access to web databases is
+  // granted by content settings. This may block and trigger a cookie prompt.
+  IPC_SYNC_MESSAGE_ROUTED4_1(ViewHostMsg_AllowDatabase,
+                             std::string /* origin_url */,
+                             string16 /* database name */,
+                             string16 /* database display name */,
+                             unsigned long /* estimated size */,
+                             bool /* result */)
+
   // Asks the browser process to open a DB file with the given name
   IPC_MESSAGE_CONTROL3(ViewHostMsg_DatabaseOpenFile,
                        string16 /* vfs file name */,
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index 81636c7..c40ef64 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -313,6 +313,7 @@ bool RenderThread::Send(IPC::Message* msg) {
         case ViewHostMsg_GetRawCookies::ID:
         case ViewHostMsg_DOMStorageSetItem::ID:
         case ViewHostMsg_SyncLoad::ID:
+        case ViewHostMsg_AllowDatabase::ID:
           may_show_cookie_prompt = true;
           pumping_events = true;
           break;
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index d8506c3..6c8b8a2 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -2936,6 +2936,21 @@ bool RenderView::allowScript(WebFrame* frame, bool enabled_per_settings) {
   return false;  // Other protocols fall through here.
 }
 
+bool RenderView::allowDatabase(
+    WebFrame* frame, const WebString& name, const WebString& display_name,
+    unsigned long estimated_size) {
+  WebSecurityOrigin origin = frame->securityOrigin();
+  if (origin.isEmpty())
+    return false;  // Uninitialized document?
+
+  bool result;
+  if (!Send(new ViewHostMsg_AllowDatabase(routing_id_,
+      origin.toString().utf8(), name, display_name, estimated_size, &result)))
+    return false;
+  if (!result)
+    DidBlockContentType(CONTENT_SETTINGS_TYPE_COOKIES);
+  return result;
+}
 void RenderView::didNotAllowScript(WebKit::WebFrame* frame) {
   DidBlockContentType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
 }
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index 370b92d..b057a9a 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -375,6 +375,9 @@ class RenderView : public RenderWidget,
   virtual void didRunInsecureContent(
       WebKit::WebFrame* frame, const WebKit::WebSecurityOrigin& origin);
   virtual bool allowScript(WebKit::WebFrame* frame, bool enabled_per_settings);
+  virtual bool allowDatabase(
+      WebKit::WebFrame* frame, const WebKit::WebString& name,
+      const WebKit::WebString& display_name, unsigned long estimated_size);
   virtual void didNotAllowScript(WebKit::WebFrame* frame);
   virtual void didNotAllowPlugins(WebKit::WebFrame* frame);
   virtual void didExhaustMemoryAvailableForScript(WebKit::WebFrame* frame);
-- 
cgit v1.1