download_query.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/download/download_query.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_path.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/case_conversion.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/string_search.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string16.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_split.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/utf_string_conversions.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/content_browser_client.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_item.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "googleurl/src/gurl.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "unicode/regex.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::DownloadDangerType;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::DownloadItem;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Templatized base::Value::GetAs*().
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <typename T> bool GetAs(const base::Value& in, T* out);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<> bool GetAs(const base::Value& in, bool* out) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return in.GetAsBoolean(out);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<> bool GetAs(const base::Value& in, int* out) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return in.GetAsInteger(out);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<> bool GetAs(const base::Value& in, std::string* out) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return in.GetAsString(out);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<> bool GetAs(const base::Value& in, string16* out) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return in.GetAsString(out);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The next several functions are helpers for making Callbacks that access
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadItem fields.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool MatchesQuery(const string16& query, const DownloadItem& item) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (query.empty())
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(query, base::i18n::ToLower(query));
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 url_raw(UTF8ToUTF16(item.GetOriginalUrl().spec()));
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::i18n::StringSearchIgnoringCaseAndAccents(
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          query, url_raw, NULL, NULL)) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 url_formatted = url_raw;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (item.GetBrowserContext()) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_formatted = net::FormatUrl(
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        item.GetOriginalUrl(),
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::GetContentClient()->browser()->GetAcceptLangs(
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            item.GetBrowserContext()));
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::i18n::StringSearchIgnoringCaseAndAccents(
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        query, url_formatted, NULL, NULL)) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 path(item.GetTargetFilePath().LossyDisplayName());
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::i18n::StringSearchIgnoringCaseAndAccents(
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      query, path, NULL, NULL);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int64 GetStartTimeMsEpoch(const DownloadItem& item) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (item.GetStartTime() - base::Time::UnixEpoch()).InMilliseconds();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(benjhayden) These timestamps don't fit in int32, and base::Value doesn't
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// support int64. Use ISO 8601 date-time strings instead.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int GetStartTime(const DownloadItem& item) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (item.GetStartTime() - base::Time::UnixEpoch()).InMilliseconds();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool GetDangerAccepted(const DownloadItem& item) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (item.GetSafetyState() == DownloadItem::DANGEROUS_BUT_VALIDATED);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static string16 GetFilename(const DownloadItem& item) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This filename will be compared with strings that could be passed in by the
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // user, who only sees LossyDisplayNames.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetTargetFilePath().LossyDisplayName();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::string GetFilenameUTF8(const DownloadItem& item) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return UTF16ToUTF8(GetFilename(item));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::string GetUrl(const DownloadItem& item) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetOriginalUrl().spec();
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static DownloadItem::DownloadState GetState(const DownloadItem& item) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetState();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static DownloadDangerType GetDangerType(const DownloadItem& item) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetDangerType();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int GetReceivedBytes(const DownloadItem& item) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetReceivedBytes();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int GetTotalBytes(const DownloadItem& item) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetTotalBytes();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::string GetMimeType(const DownloadItem& item) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.GetMimeType();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool IsPaused(const DownloadItem& item) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item.IsPaused();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum ComparisonType {LT, EQ, GT};
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |item| matches the filter specified by |value|, |cmptype|,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and |accessor|. |accessor| is conceptually a function that takes a
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadItem and returns one of its fields, which is then compared to
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |value|.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename ValueType>
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool FieldMatches(
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ValueType& value,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ComparisonType cmptype,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Callback<ValueType(const DownloadItem&)>& accessor,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DownloadItem& item) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (cmptype) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case LT: return accessor.Run(item) < value;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case EQ: return accessor.Run(item) == value;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GT: return accessor.Run(item) > value;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper for building a Callback to FieldMatches<>().
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <typename ValueType> DownloadQuery::FilterCallback BuildFilter(
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Value& value, ComparisonType cmptype,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ValueType (*accessor)(const DownloadItem&)) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ValueType cpp_value;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetAs(value, &cpp_value)) return DownloadQuery::FilterCallback();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::Bind(&FieldMatches<ValueType>, cpp_value, cmptype,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    base::Bind(accessor));
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |accessor.Run(item)| matches |pattern|.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool FindRegex(
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icu::RegexPattern* pattern,
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Callback<std::string(const DownloadItem&)>& accessor,
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DownloadItem& item) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu::UnicodeString input(accessor.Run(item).c_str());
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UErrorCode status = U_ZERO_ERROR;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<icu::RegexMatcher> matcher(pattern->matcher(input, status));
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return matcher->find() == TRUE;  // Ugh, VS complains bool != UBool.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper for building a Callback to FindRegex().
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadQuery::FilterCallback BuildRegexFilter(
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Value& regex_value,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string (*accessor)(const DownloadItem&)) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string regex_str;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetAs(regex_value, &regex_str)) return DownloadQuery::FilterCallback();
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UParseError re_err;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UErrorCode re_status = U_ZERO_ERROR;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<icu::RegexPattern> pattern(icu::RegexPattern::compile(
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icu::UnicodeString::fromUTF8(regex_str.c_str()), re_err, re_status));
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!U_SUCCESS(re_status)) return DownloadQuery::FilterCallback();
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::Bind(&FindRegex, base::Owned(pattern.release()),
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    base::Bind(accessor));
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns a ComparisonType to indicate whether a field in |left| is less than,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// greater than or equal to the same field in |right|.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename ValueType>
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ComparisonType Compare(
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Callback<ValueType(const DownloadItem&)>& accessor,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DownloadItem& left, const DownloadItem& right) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ValueType left_value = accessor.Run(left);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ValueType right_value = accessor.Run(right);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (left_value > right_value) return GT;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (left_value < right_value) return LT;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(left_value, right_value);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return EQ;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // anonymous namespace
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadQuery::DownloadQuery()
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : limit_(kuint32max) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadQuery::~DownloadQuery() {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AddFilter() pushes a new FilterCallback to filters_. Most FilterCallbacks are
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Callbacks to FieldMatches<>(). Search() iterates over given DownloadItems,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// discarding items for which any filter returns false. A DownloadQuery may have
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// zero or more FilterCallbacks.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadQuery::AddFilter(const DownloadQuery::FilterCallback& value) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (value.is_null()) return false;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filters_.push_back(value);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadQuery::AddFilter(DownloadItem::DownloadState state) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddFilter(base::Bind(&FieldMatches<DownloadItem::DownloadState>, state, EQ,
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&GetState)));
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadQuery::AddFilter(DownloadDangerType danger) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddFilter(base::Bind(&FieldMatches<DownloadDangerType>, danger, EQ,
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&GetDangerType)));
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadQuery::AddFilter(DownloadQuery::FilterType type,
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const base::Value& value) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_BYTES_RECEIVED:
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<int>(value, EQ, &GetReceivedBytes));
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_DANGER_ACCEPTED:
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<bool>(value, EQ, &GetDangerAccepted));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_FILENAME:
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<string16>(value, EQ, &GetFilename));
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_FILENAME_REGEX:
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildRegexFilter(value, &GetFilenameUTF8));
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_MIME:
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<std::string>(value, EQ, &GetMimeType));
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_PAUSED:
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<bool>(value, EQ, &IsPaused));
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_QUERY: {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string16 query;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GetAs(value, &query) &&
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             AddFilter(base::Bind(&MatchesQuery, query));
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_STARTED_AFTER:
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<int>(value, GT, &GetStartTime));
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_STARTED_BEFORE:
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<int>(value, LT, &GetStartTime));
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_START_TIME:
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<int>(value, EQ, &GetStartTime));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_TOTAL_BYTES:
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<int>(value, EQ, &GetTotalBytes));
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_TOTAL_BYTES_GREATER:
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<int>(value, GT, &GetTotalBytes));
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_TOTAL_BYTES_LESS:
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<int>(value, LT, &GetTotalBytes));
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_URL:
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildFilter<std::string>(value, EQ, &GetUrl));
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FILTER_URL_REGEX:
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AddFilter(BuildRegexFilter(value, &GetUrl));
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadQuery::Matches(const DownloadItem& item) const {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (FilterCallbackVector::const_iterator filter = filters_.begin();
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        filter != filters_.end(); ++filter) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!filter->Run(item))
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AddSorter() creates a Sorter and pushes it onto sorters_. A Sorter is a
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// direction and a Callback to Compare<>(). After filtering, Search() makes a
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadComparator functor from the sorters_ and passes the
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadComparator to std::partial_sort. std::partial_sort calls the
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadComparator with different pairs of DownloadItems.  DownloadComparator
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// iterates over the sorters until a callback returns ComparisonType LT or GT.
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadComparator returns true or false depending on that ComparisonType and
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the sorter's direction in order to indicate to std::partial_sort whether the
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// left item is after or before the right item. If all sorters return EQ, then
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadComparator compares GetId. A DownloadQuery may have zero or more
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sorters, but there is one DownloadComparator per call to Search().
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct DownloadQuery::Sorter {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef base::Callback<ComparisonType(
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const DownloadItem&, const DownloadItem&)> SortType;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template<typename ValueType>
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static Sorter Build(DownloadQuery::SortDirection adirection,
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         ValueType (*accessor)(const DownloadItem&)) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Sorter(adirection, base::Bind(&Compare<ValueType>,
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(accessor)));
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Sorter(DownloadQuery::SortDirection adirection,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const SortType& asorter)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : direction(adirection),
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorter(asorter) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~Sorter() {}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadQuery::SortDirection direction;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SortType sorter;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DownloadQuery::DownloadComparator {
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit DownloadComparator(const DownloadQuery::SorterVector& terms)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : terms_(terms) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if |left| sorts before |right|.
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool operator() (const DownloadItem* left, const DownloadItem* right);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const DownloadQuery::SorterVector& terms_;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // std::sort requires this class to be copyable.
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadQuery::DownloadComparator::operator() (
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DownloadItem* left, const DownloadItem* right) {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (DownloadQuery::SorterVector::const_iterator term = terms_.begin();
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       term != terms_.end(); ++term) {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (term->sorter.Run(*left, *right)) {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case LT: return term->direction == DownloadQuery::ASCENDING;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case GT: return term->direction == DownloadQuery::DESCENDING;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case EQ: break;  // break the switch but not the loop
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_NE(left->GetId(), right->GetId());
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return left->GetId() < right->GetId();
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadQuery::AddSorter(DownloadQuery::SortType type,
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              DownloadQuery::SortDirection direction) {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_START_TIME:
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<int64>(direction, &GetStartTimeMsEpoch));
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_URL:
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<std::string>(direction, &GetUrl));
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_FILENAME:
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<string16>(direction, &GetFilename));
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_DANGER:
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<DownloadDangerType>(
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          direction, &GetDangerType));
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_DANGER_ACCEPTED:
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<bool>(direction, &GetDangerAccepted));
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_STATE:
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<DownloadItem::DownloadState>(
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          direction, &GetState));
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_PAUSED:
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<bool>(direction, &IsPaused));
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_MIME:
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<std::string>(direction, &GetMimeType));
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_BYTES_RECEIVED:
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<int>(direction, &GetReceivedBytes));
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SORT_TOTAL_BYTES:
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorters_.push_back(Sorter::Build<int>(direction, &GetTotalBytes));
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadQuery::FinishSearch(DownloadQuery::DownloadVector* results) const {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!sorters_.empty())
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::partial_sort(results->begin(),
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      results->begin() + std::min(limit_, results->size()),
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      results->end(),
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      DownloadComparator(sorters_));
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (results->size() > limit_)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    results->resize(limit_);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
394