| 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);
|
|
|