Index: components/history/core/browser/download_database.cc |
diff --git a/components/history/core/browser/download_database.cc b/components/history/core/browser/download_database.cc |
index 42710296ae1ed9cb578c71407332812de15a9b2e..93b707c9fe22f76c0bfbac30ce721b4710e40289 100644 |
--- a/components/history/core/browser/download_database.cc |
+++ b/components/history/core/browser/download_database.cc |
@@ -186,10 +186,41 @@ bool DownloadDatabase::MigrateDownloadValidators() { |
EnsureColumnExists("last_modified", "VARCHAR NOT NULL DEFAULT \"\""); |
} |
+bool DownloadDatabase::MigrateHashHttpMethodAndGenerateGuids() { |
+ if (!EnsureColumnExists("guid", "VARCHAR NOT NULL DEFAULT ''") || |
+ !EnsureColumnExists("hash", "BLOB NOT NULL DEFAULT X''") || |
+ !EnsureColumnExists("http_method", "VARCHAR NOT NULL DEFAULT ''")) |
+ return false; |
+ |
+ // Generate GUIDs for each download. The GUID is generated thusly: |
+ // |
+ // XXXXXXXX-RRRR-RRRR-RRRR-RRRRRRRRRRRR |
+ // \__ __/ \___________ ____________/ |
+ // \/ \/ |
+ // | Random hex digits |
+ // | |
+ // Hex representation of 32-bit download ID. |
+ // |
+ // The 96 random bits provide entropy while the 32-bits from the download ID |
+ // ensure that the generated identifiers will at least be unique amongst the |
+ // download rows in the unlikely event there's a collision in the 96 entropy |
+ // bits. |
+ // |
+ // This GUID generation scheme is only used for migrated download rows and |
+ // assumes that the likelihood of a collision with a GUID generated via |
+ // base::GenerateGUID() will be vanishingly small. |
+ const char kMigrateGuidsQuery[] = |
+ "UPDATE downloads SET guid = printf" |
+ "(\"%08X-%s-%s-%s-%s\", id, hex(randomblob(2)), hex(randomblob(2))," |
+ " hex(randomblob(2)), hex(randomblob(6)))"; |
+ return GetDB().Execute(kMigrateGuidsQuery); |
+} |
+ |
bool DownloadDatabase::InitDownloadTable() { |
const char kSchema[] = |
"CREATE TABLE downloads (" |
"id INTEGER PRIMARY KEY," // Primary key. |
+ "guid VARCHAR NOT NULL," // GUID. |
"current_path LONGVARCHAR NOT NULL," // Current disk location |
"target_path LONGVARCHAR NOT NULL," // Final disk location |
"start_time INTEGER NOT NULL," // When the download was started. |
@@ -198,10 +229,12 @@ bool DownloadDatabase::InitDownloadTable() { |
"state INTEGER NOT NULL," // 1=complete, 4=interrupted |
"danger_type INTEGER NOT NULL," // Danger type, validated. |
"interrupt_reason INTEGER NOT NULL," // DownloadInterruptReason |
+ "hash BLOB NOT NULL," // Raw SHA-256 hash of contents. |
"end_time INTEGER NOT NULL," // When the download completed. |
"opened INTEGER NOT NULL," // 1 if it has ever been opened |
// else 0 |
"referrer VARCHAR NOT NULL," // HTTP Referrer |
+ "http_method VARCHAR NOT NULL," // HTTP method. |
"by_ext_id VARCHAR NOT NULL," // ID of extension that started the |
// download |
"by_ext_name VARCHAR NOT NULL," // name of extension |
@@ -257,6 +290,7 @@ bool DownloadDatabase::DropDownloadTable() { |
} |
void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) { |
+ SCOPED_UMA_HISTOGRAM_TIMER("Download.Database.QueryDownloadDuration"); |
EnsureInProgressEntriesCleanedUp(); |
results->clear(); |
@@ -264,12 +298,12 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) { |
std::map<uint32_t, DownloadRow*> info_map; |
- sql::Statement statement_main(GetDB().GetCachedStatement(SQL_FROM_HERE, |
- "SELECT id, current_path, target_path, " |
- "mime_type, original_mime_type, " |
- "start_time, received_bytes, " |
- "total_bytes, state, danger_type, interrupt_reason, end_time, opened, " |
- "referrer, by_ext_id, by_ext_name, etag, last_modified " |
+ sql::Statement statement_main(GetDB().GetCachedStatement( |
+ SQL_FROM_HERE, |
+ "SELECT id, guid, current_path, target_path, mime_type, " |
+ "original_mime_type, start_time, received_bytes, total_bytes, state, " |
+ "danger_type, interrupt_reason, hash, end_time, opened, referrer, " |
+ "http_method, by_ext_id, by_ext_name, etag, last_modified " |
"FROM downloads ORDER BY start_time")); |
while (statement_main.Step()) { |
@@ -281,6 +315,7 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) { |
// the max(id) logic in GetNextDownloadId(). |
int64_t signed_id = statement_main.ColumnInt64(column++); |
info->id = IntToDownloadId(signed_id); |
+ info->guid = statement_main.ColumnString(column++); |
info->current_path = ColumnFilePath(statement_main, column++); |
info->target_path = ColumnFilePath(statement_main, column++); |
info->mime_type = statement_main.ColumnString(column++); |
@@ -297,10 +332,12 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) { |
IntToDownloadDangerType(statement_main.ColumnInt(column++)); |
info->interrupt_reason = |
IntToDownloadInterruptReason(statement_main.ColumnInt(column++)); |
+ statement_main.ColumnBlobAsString(column++, &info->hash); |
info->end_time = |
base::Time::FromInternalValue(statement_main.ColumnInt64(column++)); |
info->opened = statement_main.ColumnInt(column++) != 0; |
info->referrer_url = GURL(statement_main.ColumnString(column++)); |
+ info->http_method = statement_main.ColumnString(column++); |
info->by_ext_id = statement_main.ColumnString(column++); |
info->by_ext_name = statement_main.ColumnString(column++); |
info->etag = statement_main.ColumnString(column++); |
@@ -390,6 +427,8 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) { |
} |
bool DownloadDatabase::UpdateDownload(const DownloadRow& data) { |
+ // UpdateDownload() is called fairly frequently. |
+ SCOPED_UMA_HISTOGRAM_TIMER("Download.Database.UpdateDownloadDuration"); |
EnsureInProgressEntriesCleanedUp(); |
DCHECK_NE(kInvalidDownloadId, data.id); |
@@ -402,12 +441,13 @@ bool DownloadDatabase::UpdateDownload(const DownloadRow& data) { |
return false; |
} |
- sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
+ sql::Statement statement(GetDB().GetCachedStatement( |
+ SQL_FROM_HERE, |
"UPDATE downloads " |
"SET current_path=?, target_path=?, " |
"mime_type=?, original_mime_type=?, " |
"received_bytes=?, state=?, " |
- "danger_type=?, interrupt_reason=?, end_time=?, total_bytes=?, " |
+ "danger_type=?, interrupt_reason=?, hash=?, end_time=?, total_bytes=?, " |
"opened=?, by_ext_id=?, by_ext_name=?, etag=?, last_modified=? " |
"WHERE id=?")); |
int column = 0; |
@@ -420,6 +460,7 @@ bool DownloadDatabase::UpdateDownload(const DownloadRow& data) { |
statement.BindInt(column++, DownloadDangerTypeToInt(data.danger_type)); |
statement.BindInt(column++, |
DownloadInterruptReasonToInt(data.interrupt_reason)); |
+ statement.BindBlob(column++, data.hash.data(), data.hash.size()); |
statement.BindInt64(column++, data.end_time.ToInternalValue()); |
statement.BindInt64(column++, data.total_bytes); |
statement.BindInt(column++, (data.opened ? 1 : 0)); |
@@ -449,6 +490,8 @@ void DownloadDatabase::EnsureInProgressEntriesCleanedUp() { |
bool DownloadDatabase::CreateDownload(const DownloadRow& info) { |
DCHECK_NE(kInvalidDownloadId, info.id); |
+ DCHECK(!info.guid.empty()); |
+ SCOPED_UMA_HISTOGRAM_TIMER("Download.Database.CreateDownloadDuration"); |
EnsureInProgressEntriesCleanedUp(); |
if (info.url_chain.empty()) |
@@ -464,16 +507,17 @@ bool DownloadDatabase::CreateDownload(const DownloadRow& info) { |
sql::Statement statement_insert(GetDB().GetCachedStatement( |
SQL_FROM_HERE, |
"INSERT INTO downloads " |
- "(id, current_path, target_path, " |
- " mime_type, original_mime_type, " |
- " start_time, " |
- " received_bytes, total_bytes, state, danger_type, interrupt_reason, " |
- " end_time, opened, referrer, by_ext_id, by_ext_name, etag, " |
- " last_modified) " |
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); |
+ "(id, guid, current_path, target_path, mime_type, original_mime_type, " |
+ " start_time, received_bytes, total_bytes, state, danger_type, " |
+ " interrupt_reason, hash, end_time, opened, referrer, http_method, " |
+ " by_ext_id, by_ext_name, etag, last_modified) " |
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " |
+ " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " |
+ " ?)")); |
int column = 0; |
statement_insert.BindInt(column++, DownloadIdToInt(info.id)); |
+ statement_insert.BindString(column++, info.guid); |
BindFilePath(statement_insert, info.current_path, column++); |
BindFilePath(statement_insert, info.target_path, column++); |
statement_insert.BindString(column++, info.mime_type); |
@@ -486,9 +530,11 @@ bool DownloadDatabase::CreateDownload(const DownloadRow& info) { |
DownloadDangerTypeToInt(info.danger_type)); |
statement_insert.BindInt( |
column++, DownloadInterruptReasonToInt(info.interrupt_reason)); |
+ statement_insert.BindBlob(column++, info.hash.data(), info.hash.size()); |
statement_insert.BindInt64(column++, info.end_time.ToInternalValue()); |
statement_insert.BindInt(column++, info.opened ? 1 : 0); |
statement_insert.BindString(column++, info.referrer_url.spec()); |
+ statement_insert.BindString(column++, info.http_method); |
statement_insert.BindString(column++, info.by_ext_id); |
statement_insert.BindString(column++, info.by_ext_name); |
statement_insert.BindString(column++, info.etag); |