diff options
Diffstat (limited to 'content')
-rw-r--r-- | content/DEPS | 1 | ||||
-rw-r--r-- | content/browser/indexed_db/indexed_db_context_impl.cc | 51 | ||||
-rw-r--r-- | content/browser/indexed_db/indexed_db_context_impl.h | 25 | ||||
-rw-r--r-- | content/browser/indexed_db/indexed_db_internals_ui.cc | 193 | ||||
-rw-r--r-- | content/browser/indexed_db/indexed_db_internals_ui.h | 22 | ||||
-rw-r--r-- | content/browser/resources/indexed_db/indexeddb_internals.html | 10 | ||||
-rw-r--r-- | content/browser/resources/indexed_db/indexeddb_internals.js | 42 | ||||
-rw-r--r-- | content/content_browser.gypi | 1 |
8 files changed, 302 insertions, 43 deletions
diff --git a/content/DEPS b/content/DEPS index fae46cf..141bb04 100644 --- a/content/DEPS +++ b/content/DEPS @@ -62,6 +62,7 @@ include_rules = [ "+third_party/tcmalloc", "+third_party/khronos", "+third_party/webrtc", + "+third_party/zlib/google", "+third_party/WebKit/Source/Platform/chromium", "+third_party/WebKit/Source/WebKit/chromium", diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc index 3c72a9e..b95be28 100644 --- a/content/browser/indexed_db/indexed_db_context_impl.cc +++ b/content/browser/indexed_db/indexed_db_context_impl.cc @@ -128,13 +128,12 @@ std::vector<IndexedDBInfo> IndexedDBContextImpl::GetAllOriginsInfo() { std::vector<IndexedDBInfo> result; for (std::vector<GURL>::const_iterator iter = origins.begin(); iter != origins.end(); ++iter) { - const GURL& origin = *iter; + const GURL& origin_url = *iter; - string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin); - base::FilePath idb_directory = GetIndexedDBFilePath(origin_id); - result.push_back(IndexedDBInfo(origin, - GetOriginDiskUsage(origin), - GetOriginLastModified(origin), + base::FilePath idb_directory = GetFilePath(origin_url); + result.push_back(IndexedDBInfo(origin_url, + GetOriginDiskUsage(origin_url), + GetOriginLastModified(origin_url), idb_directory)); } return result; @@ -150,8 +149,7 @@ int64 IndexedDBContextImpl::GetOriginDiskUsage(const GURL& origin_url) { base::Time IndexedDBContextImpl::GetOriginLastModified(const GURL& origin_url) { if (data_path_.empty() || !IsInOriginSet(origin_url)) return base::Time(); - string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url); - base::FilePath idb_directory = GetIndexedDBFilePath(origin_id); + base::FilePath idb_directory = GetFilePath(origin_url); base::PlatformFileInfo file_info; if (!file_util::GetFileInfo(idb_directory, &file_info)) return base::Time(); @@ -160,6 +158,25 @@ base::Time IndexedDBContextImpl::GetOriginLastModified(const GURL& origin_url) { void IndexedDBContextImpl::DeleteForOrigin(const GURL& origin_url) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); + ForceClose(origin_url); + if (data_path_.empty() || !IsInOriginSet(origin_url)) + return; + + base::FilePath idb_directory = GetFilePath(origin_url); + EnsureDiskUsageCacheInitialized(origin_url); + const bool recursive = true; + bool deleted = file_util::Delete(idb_directory, recursive); + + QueryDiskAndUpdateQuotaUsage(origin_url); + if (deleted) { + RemoveFromOriginSet(origin_url); + origin_size_map_.erase(origin_url); + space_available_map_.erase(origin_url); + } +} + +void IndexedDBContextImpl::ForceClose(const GURL& origin_url) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); if (data_path_.empty() || !IsInOriginSet(origin_url)) return; @@ -172,22 +189,14 @@ void IndexedDBContextImpl::DeleteForOrigin(const GURL& origin_url) { connections.erase(it++); db->forceClose(); } - DCHECK(connections_[origin_url].size() == 0); + DCHECK_EQ(connections_[origin_url].size(), 0UL); connections_.erase(origin_url); } +} +base::FilePath IndexedDBContextImpl::GetFilePath(const GURL& origin_url) { string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url); - base::FilePath idb_directory = GetIndexedDBFilePath(origin_id); - EnsureDiskUsageCacheInitialized(origin_url); - const bool recursive = true; - bool deleted = file_util::Delete(idb_directory, recursive); - - QueryDiskAndUpdateQuotaUsage(origin_url); - if (deleted) { - RemoveFromOriginSet(origin_url); - origin_size_map_.erase(origin_url); - space_available_map_.erase(origin_url); - } + return GetIndexedDBFilePath(origin_id); } base::FilePath IndexedDBContextImpl::GetFilePathForTesting( @@ -197,7 +206,7 @@ base::FilePath IndexedDBContextImpl::GetFilePathForTesting( void IndexedDBContextImpl::ConnectionOpened(const GURL& origin_url, WebIDBDatabase* connection) { - DCHECK(connections_[origin_url].count(connection) == 0); + DCHECK_EQ(connections_[origin_url].count(connection), 0UL); if (quota_manager_proxy()) { quota_manager_proxy()->NotifyStorageAccessed( quota::QuotaClient::kIndexedDatabase, origin_url, diff --git a/content/browser/indexed_db/indexed_db_context_impl.h b/content/browser/indexed_db/indexed_db_context_impl.h index 52aa57b..e40e6ae 100644 --- a/content/browser/indexed_db/indexed_db_context_impl.h +++ b/content/browser/indexed_db/indexed_db_context_impl.h @@ -54,9 +54,7 @@ class CONTENT_EXPORT IndexedDBContextImpl static const base::FilePath::CharType kIndexedDBExtension[]; // Disables the exit-time deletion of session-only data. - void SetForceKeepSessionState() { - force_keep_session_state_ = true; - } + void SetForceKeepSessionState() { force_keep_session_state_ = true; } // IndexedDBContext implementation: virtual std::vector<GURL> GetAllOrigins() OVERRIDE; @@ -64,8 +62,8 @@ class CONTENT_EXPORT IndexedDBContextImpl virtual int64 GetOriginDiskUsage(const GURL& origin_url) OVERRIDE; virtual base::Time GetOriginLastModified(const GURL& origin_url) OVERRIDE; virtual void DeleteForOrigin(const GURL& origin_url) OVERRIDE; - virtual base::FilePath GetFilePathForTesting( - const string16& origin_id) const OVERRIDE; + virtual base::FilePath GetFilePathForTesting(const string16& origin_id) const + OVERRIDE; // Methods called by IndexedDBDispatcherHost for quota support. void ConnectionOpened(const GURL& origin_url, WebKit::WebIDBDatabase*); @@ -76,7 +74,13 @@ class CONTENT_EXPORT IndexedDBContextImpl quota::QuotaManagerProxy* quota_manager_proxy(); + void ForceClose(const GURL& origin_url); + base::FilePath GetFilePath(const GURL& origin_url); base::FilePath data_path() const { return data_path_; } + bool IsInOriginSet(const GURL& origin_url) { + std::set<GURL>* set = GetOriginSet(); + return set->find(origin_url) != set->end(); + } // For unit tests allow to override the |data_path_|. void set_data_path_for_testing(const base::FilePath& data_path) { @@ -100,8 +104,10 @@ class CONTENT_EXPORT IndexedDBContextImpl int64 ReadUsageFromDisk(const GURL& origin_url) const; void EnsureDiskUsageCacheInitialized(const GURL& origin_url); void QueryDiskAndUpdateQuotaUsage(const GURL& origin_url); - void GotUsageAndQuota(const GURL& origin_url, quota::QuotaStatusCode, - int64 usage, int64 quota); + void GotUsageAndQuota(const GURL& origin_url, + quota::QuotaStatusCode, + int64 usage, + int64 quota); void GotUpdatedQuota(const GURL& origin_url, int64 usage, int64 quota); void QueryAvailableQuota(const GURL& origin_url); @@ -112,11 +118,6 @@ class CONTENT_EXPORT IndexedDBContextImpl void RemoveFromOriginSet(const GURL& origin_url) { GetOriginSet()->erase(origin_url); } - bool IsInOriginSet(const GURL& origin_url) { - std::set<GURL>* set = GetOriginSet(); - return set->find(origin_url) != set->end(); - } - // Only for testing. void ResetCaches(); diff --git a/content/browser/indexed_db/indexed_db_internals_ui.cc b/content/browser/indexed_db/indexed_db_internals_ui.cc index 1869091..4d6f04b 100644 --- a/content/browser/indexed_db/indexed_db_internals_ui.cc +++ b/content/browser/indexed_db/indexed_db_internals_ui.cc @@ -5,19 +5,30 @@ #include "content/browser/indexed_db/indexed_db_internals_ui.h" #include <algorithm> +#include <string> #include "base/bind.h" +#include "base/files/scoped_temp_dir.h" #include "base/memory/scoped_vector.h" #include "base/threading/platform_thread.h" #include "base/values.h" +#include "content/browser/indexed_db/indexed_db_context_impl.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/download_manager.h" +#include "content/public/browser/download_url_parameters.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" #include "content/public/common/url_constants.h" #include "grit/content_resources.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" +#include "third_party/zlib/google/zip.h" +#include "webkit/base/file_path_string_conversions.h" +#include "webkit/database/database_util.h" + +using webkit_database::DatabaseUtil; namespace content { @@ -27,6 +38,11 @@ IndexedDBInternalsUI::IndexedDBInternalsUI(WebUI* web_ui) "getAllOrigins", base::Bind(&IndexedDBInternalsUI::GetAllOrigins, base::Unretained(this))); + web_ui->RegisterMessageCallback( + "downloadOriginData", + base::Bind(&IndexedDBInternalsUI::DownloadOriginData, + base::Unretained(this))); + WebUIDataSource* source = WebUIDataSource::Create(kChromeUIIndexedDBInternalsHost); source->SetUseJsonJSFormatV2(); @@ -80,8 +96,8 @@ bool HostNameComparator(const IndexedDBInfo& i, const IndexedDBInfo& j) { } void IndexedDBInternalsUI::GetAllOriginsOnWebkitThread( - scoped_ptr<ContextList> contexts, - scoped_ptr<std::vector<base::FilePath> > context_paths) { + const scoped_ptr<ContextList> contexts, + const scoped_ptr<std::vector<base::FilePath> > context_paths) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); DCHECK_EQ(contexts->size(), context_paths->size()); @@ -124,4 +140,177 @@ void IndexedDBInternalsUI::OnOriginsReady( "indexeddb.onOriginsReady", urls, base::StringValue(path.value())); } +static void FindContext(const base::FilePath& partition_path, + StoragePartition** result_partition, + scoped_refptr<IndexedDBContextImpl>* result_context, + StoragePartition* storage_partition) { + if (storage_partition->GetPath() == partition_path) { + *result_partition = storage_partition; + *result_context = static_cast<IndexedDBContextImpl*>( + storage_partition->GetIndexedDBContext()); + } +} + +void IndexedDBInternalsUI::DownloadOriginData(const base::ListValue* args) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + base::FilePath::StringType path_string; + if (!args->GetString(0, &path_string)) + return; + const base::FilePath partition_path(path_string); + + std::string url_string; + if (!args->GetString(1, &url_string)) + return; + const GURL origin_url(url_string); + + // search the origins to find the right context + + BrowserContext* browser_context = + web_ui()->GetWebContents()->GetBrowserContext(); + + scoped_refptr<IndexedDBContextImpl> result_context; + StoragePartition* result_partition; + scoped_ptr<ContextList> contexts(new ContextList); + BrowserContext::StoragePartitionCallback cb = base::Bind( + &FindContext, partition_path, &result_partition, &result_context); + BrowserContext::ForEachStoragePartition(browser_context, cb); + DCHECK(result_partition); + DCHECK(result_context); + + BrowserThread::PostTask( + BrowserThread::WEBKIT_DEPRECATED, + FROM_HERE, + base::Bind(&IndexedDBInternalsUI::DownloadOriginDataOnWebkitThread, + base::Unretained(this), + result_partition->GetPath(), + result_context, + origin_url)); +} + +void IndexedDBInternalsUI::DownloadOriginDataOnWebkitThread( + const base::FilePath& partition_path, + const scoped_refptr<IndexedDBContextImpl> context, + const GURL& origin_url) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); + + if (!context->IsInOriginSet(origin_url)) + return; + + context->ForceClose(origin_url); + + base::ScopedTempDir temp_dir; + if (!temp_dir.CreateUniqueTempDir()) + return; + + // This will get cleaned up on the File thread after the download + // has completed. + base::FilePath temp_path = temp_dir.Take(); + + base::string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url); + base::FilePath::StringType zip_name = + webkit_base::WebStringToFilePathString(origin_id); + base::FilePath zip_path = + temp_path.Append(zip_name).AddExtension(FILE_PATH_LITERAL("zip")); + + // This happens on the "webkit" thread (which is really just the IndexedDB + // thread) as a simple way to avoid another script reopening the origin + // while we are zipping. + zip::Zip(context->GetFilePath(origin_url), zip_path, true); + + BrowserThread::PostTask(BrowserThread::UI, + FROM_HERE, + base::Bind(&IndexedDBInternalsUI::OnDownloadDataReady, + base::Unretained(this), + partition_path, + origin_url, + temp_path, + zip_path)); +} + +void IndexedDBInternalsUI::OnDownloadDataReady( + const base::FilePath& partition_path, + const GURL& origin_url, + const base::FilePath temp_path, + const base::FilePath zip_path) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + const GURL url = GURL(FILE_PATH_LITERAL("file://") + zip_path.value()); + BrowserContext* browser_context = + web_ui()->GetWebContents()->GetBrowserContext(); + scoped_ptr<DownloadUrlParameters> dl_params( + DownloadUrlParameters::FromWebContents(web_ui()->GetWebContents(), url)); + DownloadManager* dlm = BrowserContext::GetDownloadManager(browser_context); + + const GURL referrer(web_ui()->GetWebContents()->GetURL()); + dl_params->set_referrer( + content::Referrer(referrer, WebKit::WebReferrerPolicyDefault)); + + // This is how to watch for the download to finish: first wait for it + // to start, then attach a DownloadItem::Observer to observe the + // state change to the finished state. + dl_params->set_callback(base::Bind(&IndexedDBInternalsUI::OnDownloadStarted, + base::Unretained(this), + partition_path, + origin_url, + temp_path)); + dlm->DownloadUrl(dl_params.Pass()); +} + +// The entire purpose of this class is to delete the temp file after +// the download is complete. +class FileDeleter : public DownloadItem::Observer { + public: + explicit FileDeleter(const base::FilePath& temp_dir) : temp_dir_(temp_dir) {} + virtual ~FileDeleter(); + + virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE; + virtual void OnDownloadOpened(DownloadItem* item) OVERRIDE {} + virtual void OnDownloadRemoved(DownloadItem* item) OVERRIDE {} + virtual void OnDownloadDestroyed(DownloadItem* item) OVERRIDE {} + + private: + const base::FilePath temp_dir_; +}; + +void FileDeleter::OnDownloadUpdated(DownloadItem* item) { + switch (item->GetState()) { + case DownloadItem::IN_PROGRESS: + break; + case DownloadItem::COMPLETE: + case DownloadItem::CANCELLED: + case DownloadItem::INTERRUPTED: { + item->RemoveObserver(this); + BrowserThread::DeleteOnFileThread::Destruct(this); + break; + } + default: + NOTREACHED(); + } +} + +FileDeleter::~FileDeleter() { + base::ScopedTempDir path; + bool will_delete ALLOW_UNUSED = path.Set(temp_dir_); + DCHECK(will_delete); +} + +void IndexedDBInternalsUI::OnDownloadStarted( + const base::FilePath& partition_path, + const GURL& origin_url, + const base::FilePath& temp_path, + DownloadItem* item, + net::Error error) { + + if (error != net::OK) { + LOG(ERROR) << "Error downloading database dump: " + << net::ErrorToString(error); + return; + } + + item->AddObserver(new FileDeleter(temp_path)); + web_ui()->CallJavascriptFunction("indexeddb.onOriginDownloadReady", + base::StringValue(partition_path.value()), + base::StringValue(origin_url.spec())); +} + } // namespace content diff --git a/content/browser/indexed_db/indexed_db_internals_ui.h b/content/browser/indexed_db/indexed_db_internals_ui.h index 174db19..bc9a5da 100644 --- a/content/browser/indexed_db/indexed_db_internals_ui.h +++ b/content/browser/indexed_db/indexed_db_internals_ui.h @@ -11,11 +11,14 @@ #include "base/memory/scoped_ptr.h" #include "content/public/browser/indexed_db_context.h" #include "content/public/browser/web_ui_controller.h" +#include "net/base/net_errors.h" namespace base { class ListValue; } namespace content { +class DownloadItem; +class IndexedDBContextImpl; class StoragePartition; // The implementation for the chrome://indexeddb-internals page. @@ -28,8 +31,8 @@ class IndexedDBInternalsUI : public WebUIController { typedef std::vector<scoped_refptr<IndexedDBContext> > ContextList; void GetAllOrigins(const base::ListValue* args); void GetAllOriginsOnWebkitThread( - scoped_ptr<ContextList> contexts, - scoped_ptr<std::vector<base::FilePath> > context_paths); + const scoped_ptr<ContextList> contexts, + const scoped_ptr<std::vector<base::FilePath> > context_paths); void OnOriginsReady(scoped_ptr<std::vector<IndexedDBInfo> > origins, const base::FilePath& path); @@ -37,6 +40,21 @@ class IndexedDBInternalsUI : public WebUIController { std::vector<base::FilePath>* paths, StoragePartition* partition); + void DownloadOriginData(const base::ListValue* args); + void DownloadOriginDataOnWebkitThread( + const base::FilePath& partition_path, + const scoped_refptr<IndexedDBContextImpl> context, + const GURL& origin_url); + void OnDownloadDataReady(const base::FilePath& partition_path, + const GURL& origin_url, + const base::FilePath temp_path, + const base::FilePath zip_path); + void OnDownloadStarted(const base::FilePath& partition_path, + const GURL& origin_url, + const base::FilePath& temp_path, + content::DownloadItem* item, + net::Error error); + DISALLOW_COPY_AND_ASSIGN(IndexedDBInternalsUI); }; diff --git a/content/browser/resources/indexed_db/indexeddb_internals.html b/content/browser/resources/indexed_db/indexeddb_internals.html index 5db358d..87337ec 100644 --- a/content/browser/resources/indexed_db/indexeddb_internals.html +++ b/content/browser/resources/indexed_db/indexeddb_internals.html @@ -10,10 +10,11 @@ <body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize"> <!-- templates --> <div style="display:none"> - <div id="indexeddb-list-template"> + <div id="indexeddb-list-template" + jsvalues="$partition_path:$this.partition_path"> <div class="indexeddb-summary"> <span>Instances in: </span> - <span jscontent="$this.path"></span> + <span jscontent="$this.partition_path"></span> <span jscontent="'(' + $this.idbs.length + ')'"></span> </div> <div class="indexeddb-item" jsselect="$this.idbs"> @@ -31,6 +32,11 @@ <span>Path:</span> <span jscontent="path"></span> </div> + <div class="controls"> + <a href="#" class="download" + jsvalues=".idb_origin_url:url;.idb_partition_path:$partition_path">Download</a> + <span class="download-status" style="display: none">Loading...</span> + </div> </div> </div> </div> diff --git a/content/browser/resources/indexed_db/indexeddb_internals.js b/content/browser/resources/indexed_db/indexeddb_internals.js index 9bc3b0b..378b9ad 100644 --- a/content/browser/resources/indexed_db/indexeddb_internals.js +++ b/content/browser/resources/indexed_db/indexeddb_internals.js @@ -9,16 +9,50 @@ cr.define('indexeddb', function() { chrome.send('getAllOrigins'); } - function onOriginsReady(origins, path) { + function progressNodeFor(link) { + return link.parentNode.querySelector('.download-status'); + } + + function downloadOriginData(event) { + var link = event.target; + progressNodeFor(link).style.display = 'inline'; + chrome.send('downloadOriginData', [link.idb_partition_path, + link.idb_origin_url]); + return false; + } + + // Fired from the backend after the data has been zipped up, and the + // download manager has begun downloading the file. + function onOriginDownloadReady(partition_path, origin_url) { + var downloadLinks = document.querySelectorAll('a.download'); + for (var i = 0; i < downloadLinks.length; ++i) { + var link = downloadLinks[i]; + if (partition_path == link.idb_partition_path && + origin_url == link.idb_origin_url) { + progressNodeFor(link).style.display = 'none'; + } + } + } + + // Fired from the backend with a single partition's worth of + // IndexedDB metadata. + function onOriginsReady(origins, partition_path) { var template = jstGetTemplate('indexeddb-list-template'); var container = $('indexeddb-list'); container.appendChild(template); - jstProcess(new JsEvalContext({ idbs: origins, path: path}), template); + jstProcess(new JsEvalContext({ idbs: origins, + partition_path: partition_path}), template); + + var downloadLinks = container.querySelectorAll('a.download'); + for (var i = 0; i < downloadLinks.length; ++i) { + downloadLinks[i].addEventListener('click', downloadOriginData, false); + } } return { - initialize: initialize, - onOriginsReady: onOriginsReady, + initialize: initialize, + onOriginDownloadReady: onOriginDownloadReady, + onOriginsReady: onOriginsReady, }; }); diff --git a/content/content_browser.gypi b/content/content_browser.gypi index b00f0e8..8fcfbc3 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -12,6 +12,7 @@ '../skia/skia.gyp:skia', '../sql/sql.gyp:sql', '../third_party/re2/re2.gyp:re2', + '../third_party/zlib/zlib.gyp:zip', '../third_party/zlib/zlib.gyp:zlib', '../ui/snapshot/snapshot.gyp:snapshot', '../ui/ui.gyp:ui', |