blob: 0b1e3cfc6af094a0a22411fc65ca33de764f9f71 [file]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/android/history_report/delta_file_commons.h"
#include <stddef.h>
#include <iomanip>
#include <sstream>
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/browser/url_and_title.h"
#include "crypto/sha2.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
using bookmarks::BookmarkModel;
using bookmarks::UrlAndTitle;
using net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES;
using net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES;
using net::registry_controlled_domains::GetCanonicalHostRegistryLength;
namespace {
const int kBookmarkScoreBonusMultiplier = 3;
const size_t kIdLengthLimit = 256;
const int kSHA256ByteSize = 32;
const size_t kUrlLengthLimit = 20 * 1024 * 1024; // 20M
const size_t kUrlLengthWidth = 8;
void StripTopLevelDomain(std::string* canonical_host) {
size_t registry_length = GetCanonicalHostRegistryLength(
*canonical_host, EXCLUDE_UNKNOWN_REGISTRIES, EXCLUDE_PRIVATE_REGISTRIES);
if (registry_length != 0 && registry_length != std::string::npos)
canonical_host->erase(canonical_host->length() - (registry_length + 1));
}
void StripCommonSubDomains(std::string* host) {
std::string www_prefix("www.");
std::string ww2_prefix("ww2.");
if (host->compare(0, www_prefix.size(), www_prefix) == 0) {
host->erase(0, www_prefix.size());
} else if (host->compare(0, ww2_prefix.size(), ww2_prefix) == 0) {
host->erase(0, ww2_prefix.size());
}
}
} // namespace
namespace history_report {
DeltaFileEntryWithData::DeltaFileEntryWithData(DeltaFileEntry entry)
: entry_(entry),
data_set_(false),
is_bookmark_(false) {}
DeltaFileEntryWithData::DeltaFileEntryWithData(
const DeltaFileEntryWithData& other) = default;
DeltaFileEntryWithData::~DeltaFileEntryWithData() {}
int64_t DeltaFileEntryWithData::SeqNo() const {
return entry_.seq_no();
}
std::string DeltaFileEntryWithData::Type() const {
// If deletion entry has data then it's not a real deletion entry
// but an update entry. Real deletion entry never has data.
if (data_set_) return "add";
return entry_.type();
}
// Generates a unique ID for a given URL.
// It must be shorter than or equal to |kIdLengthLimit| characters.
// If URL is shorter than or equal to |kIdLengthLimit| then ID is the URL
// itself. Otherwise it has a form of 3 concatenated parts:
// 1. Length of URL. Zero-padded integer to width |kUrlLengthWidth|,
// because URLs are limited to 20M in Chrome.
// 2. SHA-256 of URL which takes 64 characters.
// 3. Prefix of URL of size |kIdLengthLimit| - 64 - |kUrlLengthWidth|.
std::string DeltaFileEntryWithData::UrlToId(const std::string& url) {
if (url.size() > kUrlLengthLimit) {
return "error: url too long";
}
if (IsValidId(url)) {
return url;
}
std::stringstream id;
// 1. Zero-padded URL length to width |kUrlLengthWidth|.
id << std::setfill('0') << std::setw(kUrlLengthWidth) << url.size();
// 2. SHA-256 of URL.
uint8_t hash[kSHA256ByteSize];
crypto::SHA256HashString(url, hash, sizeof(hash));
id << base::HexEncode(hash, sizeof(hash));
// 3. Prefix of URL to fill rest of the space.
id << url.substr(0, kIdLengthLimit - 2 * kSHA256ByteSize - kUrlLengthWidth);
return id.str();
}
// ID which identifies URL of this entry.
std::string DeltaFileEntryWithData::Id() const {
return UrlToId(entry_.url());
}
std::string DeltaFileEntryWithData::Url() const {
return entry_.url();
}
base::string16 DeltaFileEntryWithData::Title() const {
if (!Valid()) return base::UTF8ToUTF16("");
if (is_bookmark_ && !bookmark_title_.empty()) return bookmark_title_;
if (data_.title().empty()) return base::UTF8ToUTF16(data_.url().host_piece());
return data_.title();
}
int32_t DeltaFileEntryWithData::Score() const {
if (!Valid()) return 0;
int32_t score = data_.visit_count() + data_.typed_count();
if (is_bookmark_) score = (score + 1) * kBookmarkScoreBonusMultiplier;
return score;
}
std::string DeltaFileEntryWithData::IndexedUrl() const {
if (!Valid()) return "";
std::string indexed_url = data_.url().host();
StripTopLevelDomain(&indexed_url);
StripCommonSubDomains(&indexed_url);
return indexed_url;
}
bool DeltaFileEntryWithData::Valid() const {
return entry_.type() == "del" || is_bookmark_ ||
(data_set_ && !data_.hidden());
}
void DeltaFileEntryWithData::SetData(const history::URLRow& data) {
data_set_ = true;
data_ = data;
}
void DeltaFileEntryWithData::MarkAsBookmark(const UrlAndTitle& bookmark) {
is_bookmark_ = true;
bookmark_title_ = bookmark.title;
}
// static
bool DeltaFileEntryWithData::IsValidId(const std::string& url) {
return url.size() <= kIdLengthLimit;
}
} // namespace history_report