Chromium Code Reviews| Index: chrome/browser/history/top_sites_database.cc |
| diff --git a/chrome/browser/history/top_sites_database.cc b/chrome/browser/history/top_sites_database.cc |
| index ff20d4db8e3756beaeec1e264ac13030bced5bce..386875f8baf8049b395b6ac9694559823364bcf1 100644 |
| --- a/chrome/browser/history/top_sites_database.cc |
| +++ b/chrome/browser/history/top_sites_database.cc |
| @@ -78,22 +78,6 @@ bool InitTables(sql::Connection* db) { |
| return db->Execute(kThumbnailsSql); |
| } |
| -// Encodes redirects into a string. |
| -std::string GetRedirects(const history::MostVisitedURL& url) { |
| - std::vector<std::string> redirects; |
| - for (size_t i = 0; i < url.redirects.size(); i++) |
| - redirects.push_back(url.redirects[i].spec()); |
| - return JoinString(redirects, ' '); |
| -} |
| - |
| -// Decodes redirects from a string and sets them for the url. |
| -void SetRedirects(const std::string& redirects, history::MostVisitedURL* url) { |
| - std::vector<std::string> redirects_vector; |
| - base::SplitStringAlongWhitespace(redirects, &redirects_vector); |
| - for (size_t i = 0; i < redirects_vector.size(); ++i) |
| - url->redirects.push_back(GURL(redirects_vector[i])); |
| -} |
| - |
| // Track various failure (and success) cases in recovery code. |
| // |
| // TODO(shess): The recovery code is complete, but by nature runs in challenging |
| @@ -132,6 +116,8 @@ enum RecoveryEventType { |
| RECOVERY_EVENT_MAX, |
| }; |
| +const char kDataUrlPrefix[] = "data:"; |
| + |
| void RecordRecoveryEvent(RecoveryEventType recovery_event) { |
| UMA_HISTOGRAM_ENUMERATION("History.TopSitesRecovery", |
| recovery_event, RECOVERY_EVENT_MAX); |
| @@ -460,8 +446,8 @@ void TopSitesDatabase::GetPageThumbnails(MostVisitedURLList* urls, |
| url.title = statement.ColumnString16(2); |
| url.last_forced_time = |
| base::Time::FromInternalValue(statement.ColumnInt64(10)); |
| - std::string redirects = statement.ColumnString(4); |
| - SetRedirects(redirects, &url); |
| + std::string encoded_redirects = statement.ColumnString(4); |
| + DecodeRedirects(encoded_redirects, &url.redirects); |
| urls->push_back(url); |
| std::vector<unsigned char> data; |
| @@ -510,7 +496,7 @@ bool TopSitesDatabase::UpdatePageThumbnail( |
| statement.BindBlob(1, thumbnail.thumbnail->front(), |
| static_cast<int>(thumbnail.thumbnail->size())); |
| } |
| - statement.BindString(2, GetRedirects(url)); |
| + statement.BindString(2, EncodeRedirects(url.redirects)); |
| const ThumbnailScore& score = thumbnail.thumbnail_score; |
| statement.BindDouble(3, score.boring_score); |
| statement.BindBool(4, score.good_clipping); |
| @@ -539,7 +525,7 @@ void TopSitesDatabase::AddPageThumbnail(const MostVisitedURL& url, |
| statement.BindBlob(3, thumbnail.thumbnail->front(), |
| static_cast<int>(thumbnail.thumbnail->size())); |
| } |
| - statement.BindString(4, GetRedirects(url)); |
| + statement.BindString(4, EncodeRedirects(url.redirects)); |
| const ThumbnailScore& score = thumbnail.thumbnail_score; |
| statement.BindDouble(5, score.boring_score); |
| statement.BindBool(6, score.good_clipping); |
| @@ -559,6 +545,102 @@ void TopSitesDatabase::AddPageThumbnail(const MostVisitedURL& url, |
| UpdatePageRankNoTransaction(url, new_rank); |
| } |
| +// static |
| +std::string TopSitesDatabase::EncodeCSVString( |
| + const std::vector<std::string> str_list) { |
| + std::string csv; |
| + for (std::vector<std::string>::const_iterator it = str_list.begin(); |
| + it != str_list.end(); ++it) { |
| + const std::string& str = *it; |
| + if (it != str_list.begin()) |
| + csv += ','; |
| + csv += '"'; |
| + for (std::string::const_iterator jt = str.begin(); jt != str.end(); ++jt) { |
| + if (*jt == '"') |
| + csv += '"'; |
|
beaudoin
2014/09/09 21:32:27
Looks like you escape quotes as two quotes. Your c
huangs
2014/09/11 01:58:13
Comment in .h file updated.
|
| + csv += *jt; |
| + } |
| + csv += '"'; |
| + } |
| + return csv; |
| +} |
| + |
| +// static |
| +bool TopSitesDatabase::DecodeCSVString(const std::string csv, |
| + std::vector<std::string>* str_list) { |
| + if (csv.empty()) { |
| + str_list->clear(); |
| + return true; |
| + } |
| + |
| + enum { |
| + SEEK_QUOTE, |
| + READ_STRING, |
| + SAW_ONE_QUOTE |
| + } state = SEEK_QUOTE; |
| + std::vector<std::string> out_list; |
| + std::string str; |
| + for (std::string::const_iterator it = csv.begin(); it != csv.end(); ++it) { |
| + const char ch = *it; |
| + if (state == SEEK_QUOTE) { |
| + if (ch != '"') |
| + return false; |
| + state = READ_STRING; |
| + } else if (state == READ_STRING) { |
| + if (ch == '"') |
| + state = SAW_ONE_QUOTE; |
| + else |
| + str += ch; |
| + } else if (state == SAW_ONE_QUOTE) { |
| + if (ch == '"') { |
| + str += ch; |
| + state = READ_STRING; |
| + } else if (ch == ',') { |
| + out_list.push_back(str); |
| + str.clear(); |
| + state = SEEK_QUOTE; |
| + } else { |
| + return false; |
|
beaudoin
2014/09/09 21:32:27
You're strict about the fact that the comma must i
huangs
2014/09/11 01:58:13
Done.
|
| + } |
| + } else { |
| + NOTREACHED(); |
| + return false; |
| + } |
| + } |
| + if (state != SAW_ONE_QUOTE) |
| + return false; |
| + out_list.push_back(str); |
| + str_list->swap(out_list); |
| + return true; |
| +} |
| + |
| +// static |
| +std::string TopSitesDatabase::EncodeRedirects(const RedirectList& redirects) { |
| + std::vector<std::string> valid_urls; |
| + for (size_t i = 0; i < redirects.size(); i++) { |
| + // Example of invalid URL that may end up here: |
| + // "data:text/plain,this string contains space". |
| + if (redirects[i].is_valid()) |
| + valid_urls.push_back(redirects[i].spec()); |
| + } |
| + return EncodeCSVString(valid_urls); |
| +} |
| + |
| +// static |
| +void TopSitesDatabase::DecodeRedirects(const std::string& encoded_redirects, |
| + RedirectList* redirects) { |
| + std::vector<std::string> redirects_vector; |
| + if (!DecodeCSVString(encoded_redirects, &redirects_vector)) { |
| + // Fall back to space-delimited list for backward compatibility. |
| + base::SplitStringAlongWhitespace(encoded_redirects, &redirects_vector); |
|
beaudoin
2014/09/09 21:32:27
I see, so you support DB in the old format too. It
huangs
2014/09/11 01:58:13
Changing version, but have to maintain backward co
|
| + } |
| + for (size_t i = 0; i < redirects_vector.size(); ++i) { |
| + GURL redirect_url(redirects_vector[i]); |
| + if (redirect_url.is_valid()) |
| + redirects->push_back(redirect_url); |
| + } |
| +} |
| + |
| void TopSitesDatabase::UpdatePageRank(const MostVisitedURL& url, |
| int new_rank) { |
| DCHECK((url.last_forced_time.ToInternalValue() == 0) == |