This source file includes following definitions.
- GetAs
- GetAs
- GetAs
- GetAs
- GetAs
- MatchesQuery
- GetStartTimeMsEpoch
- GetEndTimeMsEpoch
- TimeToISO8601
- GetStartTime
- GetEndTime
- GetDangerAccepted
- GetExists
- GetFilename
- GetFilenameUTF8
- GetUrl
- GetState
- GetDangerType
- GetReceivedBytes
- GetTotalBytes
- GetMimeType
- IsPaused
- FieldMatches
- BuildFilter
- FindRegex
- BuildRegexFilter
- Compare
- AddFilter
- AddFilter
- AddFilter
- AddFilter
- Matches
- DownloadComparator
- AddSorter
- FinishSearch
#include "chrome/browser/download/download_query.h"
#include <algorithm>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/i18n/case_conversion.h"
#include "base/i18n/string_search.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_service.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/download_item.h"
#include "net/base/net_util.h"
#include "third_party/re2/re2/re2.h"
#include "url/gurl.h"
using content::DownloadDangerType;
using content::DownloadItem;
namespace {
template <typename T> bool GetAs(const base::Value& in, T* out);
template<> bool GetAs(const base::Value& in, bool* out) {
return in.GetAsBoolean(out);
}
template<> bool GetAs(const base::Value& in, int* out) {
return in.GetAsInteger(out);
}
template<> bool GetAs(const base::Value& in, std::string* out) {
return in.GetAsString(out);
}
template<> bool GetAs(const base::Value& in, base::string16* out) {
return in.GetAsString(out);
}
template<> bool GetAs(const base::Value& in, std::vector<base::string16>* out) {
out->clear();
const base::ListValue* list = NULL;
if (!in.GetAsList(&list))
return false;
for (size_t i = 0; i < list->GetSize(); ++i) {
base::string16 element;
if (!list->GetString(i, &element)) {
out->clear();
return false;
}
out->push_back(element);
}
return true;
}
static bool MatchesQuery(
const std::vector<base::string16>& query_terms,
const DownloadItem& item) {
DCHECK(!query_terms.empty());
base::string16 url_raw(base::UTF8ToUTF16(item.GetOriginalUrl().spec()));
base::string16 url_formatted = url_raw;
if (item.GetBrowserContext()) {
Profile* profile = Profile::FromBrowserContext(item.GetBrowserContext());
url_formatted = net::FormatUrl(
item.GetOriginalUrl(),
profile->GetPrefs()->GetString(prefs::kAcceptLanguages));
}
base::string16 path(item.GetTargetFilePath().LossyDisplayName());
for (std::vector<base::string16>::const_iterator it = query_terms.begin();
it != query_terms.end(); ++it) {
base::string16 term = base::i18n::ToLower(*it);
if (!base::i18n::StringSearchIgnoringCaseAndAccents(
term, url_raw, NULL, NULL) &&
!base::i18n::StringSearchIgnoringCaseAndAccents(
term, url_formatted, NULL, NULL) &&
!base::i18n::StringSearchIgnoringCaseAndAccents(
term, path, NULL, NULL)) {
return false;
}
}
return true;
}
static int64 GetStartTimeMsEpoch(const DownloadItem& item) {
return (item.GetStartTime() - base::Time::UnixEpoch()).InMilliseconds();
}
static int64 GetEndTimeMsEpoch(const DownloadItem& item) {
return (item.GetEndTime() - base::Time::UnixEpoch()).InMilliseconds();
}
std::string TimeToISO8601(const base::Time& t) {
base::Time::Exploded exploded;
t.UTCExplode(&exploded);
return base::StringPrintf(
"%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", exploded.year, exploded.month,
exploded.day_of_month, exploded.hour, exploded.minute, exploded.second,
exploded.millisecond);
}
static std::string GetStartTime(const DownloadItem& item) {
return TimeToISO8601(item.GetStartTime());
}
static std::string GetEndTime(const DownloadItem& item) {
return TimeToISO8601(item.GetEndTime());
}
static bool GetDangerAccepted(const DownloadItem& item) {
return (item.GetDangerType() ==
content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED);
}
static bool GetExists(const DownloadItem& item) {
return !item.GetFileExternallyRemoved();
}
static base::string16 GetFilename(const DownloadItem& item) {
return item.GetTargetFilePath().LossyDisplayName();
}
static std::string GetFilenameUTF8(const DownloadItem& item) {
return base::UTF16ToUTF8(GetFilename(item));
}
static std::string GetUrl(const DownloadItem& item) {
return item.GetOriginalUrl().spec();
}
static DownloadItem::DownloadState GetState(const DownloadItem& item) {
return item.GetState();
}
static DownloadDangerType GetDangerType(const DownloadItem& item) {
return item.GetDangerType();
}
static int GetReceivedBytes(const DownloadItem& item) {
return item.GetReceivedBytes();
}
static int GetTotalBytes(const DownloadItem& item) {
return item.GetTotalBytes();
}
static std::string GetMimeType(const DownloadItem& item) {
return item.GetMimeType();
}
static bool IsPaused(const DownloadItem& item) {
return item.IsPaused();
}
enum ComparisonType {LT, EQ, GT};
template<typename ValueType>
static bool FieldMatches(
const ValueType& value,
ComparisonType cmptype,
const base::Callback<ValueType(const DownloadItem&)>& accessor,
const DownloadItem& item) {
switch (cmptype) {
case LT: return accessor.Run(item) < value;
case EQ: return accessor.Run(item) == value;
case GT: return accessor.Run(item) > value;
}
NOTREACHED();
return false;
}
template <typename ValueType> DownloadQuery::FilterCallback BuildFilter(
const base::Value& value, ComparisonType cmptype,
ValueType (*accessor)(const DownloadItem&)) {
ValueType cpp_value;
if (!GetAs(value, &cpp_value)) return DownloadQuery::FilterCallback();
return base::Bind(&FieldMatches<ValueType>, cpp_value, cmptype,
base::Bind(accessor));
}
static bool FindRegex(
RE2* pattern,
const base::Callback<std::string(const DownloadItem&)>& accessor,
const DownloadItem& item) {
return RE2::PartialMatch(accessor.Run(item), *pattern);
}
DownloadQuery::FilterCallback BuildRegexFilter(
const base::Value& regex_value,
std::string (*accessor)(const DownloadItem&)) {
std::string regex_str;
if (!GetAs(regex_value, ®ex_str)) return DownloadQuery::FilterCallback();
scoped_ptr<RE2> pattern(new RE2(regex_str));
if (!pattern->ok()) return DownloadQuery::FilterCallback();
return base::Bind(&FindRegex, base::Owned(pattern.release()),
base::Bind(accessor));
}
template<typename ValueType>
static ComparisonType Compare(
const base::Callback<ValueType(const DownloadItem&)>& accessor,
const DownloadItem& left, const DownloadItem& right) {
ValueType left_value = accessor.Run(left);
ValueType right_value = accessor.Run(right);
if (left_value > right_value) return GT;
if (left_value < right_value) return LT;
DCHECK_EQ(left_value, right_value);
return EQ;
}
}
DownloadQuery::DownloadQuery()
: limit_(kuint32max) {
}
DownloadQuery::~DownloadQuery() {
}
bool DownloadQuery::AddFilter(const DownloadQuery::FilterCallback& value) {
if (value.is_null()) return false;
filters_.push_back(value);
return true;
}
void DownloadQuery::AddFilter(DownloadItem::DownloadState state) {
AddFilter(base::Bind(&FieldMatches<DownloadItem::DownloadState>, state, EQ,
base::Bind(&GetState)));
}
void DownloadQuery::AddFilter(DownloadDangerType danger) {
AddFilter(base::Bind(&FieldMatches<DownloadDangerType>, danger, EQ,
base::Bind(&GetDangerType)));
}
bool DownloadQuery::AddFilter(DownloadQuery::FilterType type,
const base::Value& value) {
switch (type) {
case FILTER_BYTES_RECEIVED:
return AddFilter(BuildFilter<int>(value, EQ, &GetReceivedBytes));
case FILTER_DANGER_ACCEPTED:
return AddFilter(BuildFilter<bool>(value, EQ, &GetDangerAccepted));
case FILTER_EXISTS:
return AddFilter(BuildFilter<bool>(value, EQ, &GetExists));
case FILTER_FILENAME:
return AddFilter(BuildFilter<base::string16>(value, EQ, &GetFilename));
case FILTER_FILENAME_REGEX:
return AddFilter(BuildRegexFilter(value, &GetFilenameUTF8));
case FILTER_MIME:
return AddFilter(BuildFilter<std::string>(value, EQ, &GetMimeType));
case FILTER_PAUSED:
return AddFilter(BuildFilter<bool>(value, EQ, &IsPaused));
case FILTER_QUERY: {
std::vector<base::string16> query_terms;
return GetAs(value, &query_terms) &&
(query_terms.empty() ||
AddFilter(base::Bind(&MatchesQuery, query_terms)));
}
case FILTER_ENDED_AFTER:
return AddFilter(BuildFilter<std::string>(value, GT, &GetEndTime));
case FILTER_ENDED_BEFORE:
return AddFilter(BuildFilter<std::string>(value, LT, &GetEndTime));
case FILTER_END_TIME:
return AddFilter(BuildFilter<std::string>(value, EQ, &GetEndTime));
case FILTER_STARTED_AFTER:
return AddFilter(BuildFilter<std::string>(value, GT, &GetStartTime));
case FILTER_STARTED_BEFORE:
return AddFilter(BuildFilter<std::string>(value, LT, &GetStartTime));
case FILTER_START_TIME:
return AddFilter(BuildFilter<std::string>(value, EQ, &GetStartTime));
case FILTER_TOTAL_BYTES:
return AddFilter(BuildFilter<int>(value, EQ, &GetTotalBytes));
case FILTER_TOTAL_BYTES_GREATER:
return AddFilter(BuildFilter<int>(value, GT, &GetTotalBytes));
case FILTER_TOTAL_BYTES_LESS:
return AddFilter(BuildFilter<int>(value, LT, &GetTotalBytes));
case FILTER_URL:
return AddFilter(BuildFilter<std::string>(value, EQ, &GetUrl));
case FILTER_URL_REGEX:
return AddFilter(BuildRegexFilter(value, &GetUrl));
}
return false;
}
bool DownloadQuery::Matches(const DownloadItem& item) const {
for (FilterCallbackVector::const_iterator filter = filters_.begin();
filter != filters_.end(); ++filter) {
if (!filter->Run(item))
return false;
}
return true;
}
struct DownloadQuery::Sorter {
typedef base::Callback<ComparisonType(
const DownloadItem&, const DownloadItem&)> SortType;
template<typename ValueType>
static Sorter Build(DownloadQuery::SortDirection adirection,
ValueType (*accessor)(const DownloadItem&)) {
return Sorter(adirection, base::Bind(&Compare<ValueType>,
base::Bind(accessor)));
}
Sorter(DownloadQuery::SortDirection adirection,
const SortType& asorter)
: direction(adirection),
sorter(asorter) {
}
~Sorter() {}
DownloadQuery::SortDirection direction;
SortType sorter;
};
class DownloadQuery::DownloadComparator {
public:
explicit DownloadComparator(const DownloadQuery::SorterVector& terms)
: terms_(terms) {
}
bool operator() (const DownloadItem* left, const DownloadItem* right);
private:
const DownloadQuery::SorterVector& terms_;
};
bool DownloadQuery::DownloadComparator::operator() (
const DownloadItem* left, const DownloadItem* right) {
for (DownloadQuery::SorterVector::const_iterator term = terms_.begin();
term != terms_.end(); ++term) {
switch (term->sorter.Run(*left, *right)) {
case LT: return term->direction == DownloadQuery::ASCENDING;
case GT: return term->direction == DownloadQuery::DESCENDING;
case EQ: break;
}
}
CHECK_NE(left->GetId(), right->GetId());
return left->GetId() < right->GetId();
}
void DownloadQuery::AddSorter(DownloadQuery::SortType type,
DownloadQuery::SortDirection direction) {
switch (type) {
case SORT_END_TIME:
sorters_.push_back(Sorter::Build<int64>(direction, &GetEndTimeMsEpoch));
break;
case SORT_START_TIME:
sorters_.push_back(Sorter::Build<int64>(direction, &GetStartTimeMsEpoch));
break;
case SORT_URL:
sorters_.push_back(Sorter::Build<std::string>(direction, &GetUrl));
break;
case SORT_FILENAME:
sorters_.push_back(
Sorter::Build<base::string16>(direction, &GetFilename));
break;
case SORT_DANGER:
sorters_.push_back(Sorter::Build<DownloadDangerType>(
direction, &GetDangerType));
break;
case SORT_DANGER_ACCEPTED:
sorters_.push_back(Sorter::Build<bool>(direction, &GetDangerAccepted));
break;
case SORT_EXISTS:
sorters_.push_back(Sorter::Build<bool>(direction, &GetExists));
break;
case SORT_STATE:
sorters_.push_back(Sorter::Build<DownloadItem::DownloadState>(
direction, &GetState));
break;
case SORT_PAUSED:
sorters_.push_back(Sorter::Build<bool>(direction, &IsPaused));
break;
case SORT_MIME:
sorters_.push_back(Sorter::Build<std::string>(direction, &GetMimeType));
break;
case SORT_BYTES_RECEIVED:
sorters_.push_back(Sorter::Build<int>(direction, &GetReceivedBytes));
break;
case SORT_TOTAL_BYTES:
sorters_.push_back(Sorter::Build<int>(direction, &GetTotalBytes));
break;
}
}
void DownloadQuery::FinishSearch(DownloadQuery::DownloadVector* results) const {
if (!sorters_.empty())
std::partial_sort(results->begin(),
results->begin() + std::min(limit_, results->size()),
results->end(),
DownloadComparator(sorters_));
if (results->size() > limit_)
results->resize(limit_);
}