Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/browser/download/download_query.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/memory/scoped_ptr.h" | |
| 11 #include "base/stl_util.h" | |
| 12 #include "base/string16.h" | |
| 13 #include "base/string_split.h" | |
| 14 #include "base/values.h" | |
| 15 #include "unicode/regex.h" | |
| 16 #include "content/browser/download/download_item.h" | |
| 17 | |
| 18 namespace { | |
| 19 typedef std::vector<std::string> Strings; | |
| 20 typedef std::vector<DownloadItem*> DownloadItems; | |
| 21 | |
| 22 struct SimpleDownloadItem { | |
| 23 static const char STATE_IN_PROGRESS[]; | |
| 24 static const char STATE_COMPLETE[]; | |
| 25 static const char STATE_INTERRUPTED[]; | |
| 26 static const char DANGER_SAFE[]; | |
| 27 static const char DANGER_FILE[]; | |
| 28 static const char DANGER_URL[]; | |
| 29 | |
| 30 explicit SimpleDownloadItem(DownloadItem* download) | |
| 31 : item(download) { | |
| 32 CHECK(item); | |
| 33 } | |
| 34 | |
| 35 int id() const { return item->id(); } | |
| 36 std::string url() const { return item->original_url().spec(); } | |
| 37 std::string filename() const { | |
| 38 return item->GetFileNameToReportUser().value(); | |
| 39 } | |
| 40 std::string danger() const { return DangerString(item->GetDangerType()); } | |
| 41 bool dangerAccepted() const { | |
| 42 return item->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED; | |
| 43 } | |
| 44 std::string state() const { return StateString(item->state()); } | |
| 45 bool paused() const { return item->is_paused(); } | |
| 46 std::string mime() const { return item->mime_type(); } | |
| 47 int startTime() const { | |
| 48 return (item->start_time() - base::Time::UnixEpoch()).InMilliseconds(); | |
| 49 } | |
| 50 int endTime() const { return -1; } | |
| 51 int bytesReceived() const { return item->received_bytes(); } | |
| 52 int totalBytes() const { return item->total_bytes(); } | |
| 53 int fileSize() const { return -1; } | |
| 54 int error() const { return 0; } | |
| 55 | |
| 56 base::DictionaryValue* ToJSON() const; | |
| 57 | |
| 58 static std::string DangerString(DownloadItem::DangerType danger) { | |
| 59 switch (danger) { | |
| 60 case DownloadItem::NOT_DANGEROUS: return DANGER_SAFE; | |
| 61 case DownloadItem::DANGEROUS_FILE: return DANGER_FILE; | |
| 62 case DownloadItem::DANGEROUS_URL: return DANGER_URL; | |
| 63 case DownloadItem::DANGEROUS_TYPE_MAX: | |
| 64 default: | |
| 65 NOTREACHED(); | |
| 66 return ""; | |
| 67 } | |
| 68 } | |
| 69 | |
| 70 static std::string StateString(DownloadItem::DownloadState state) { | |
| 71 switch (state) { | |
| 72 case DownloadItem::IN_PROGRESS: return STATE_IN_PROGRESS; | |
| 73 case DownloadItem::COMPLETE: return STATE_COMPLETE; | |
| 74 case DownloadItem::INTERRUPTED: // fall through | |
| 75 case DownloadItem::CANCELLED: return STATE_INTERRUPTED; | |
| 76 case DownloadItem::REMOVING: | |
| 77 case DownloadItem::MAX_DOWNLOAD_STATE: | |
| 78 default: | |
| 79 NOTREACHED(); | |
| 80 return ""; | |
| 81 } | |
| 82 } | |
| 83 | |
| 84 DownloadItem* item; | |
| 85 // Allow copy and assign. | |
| 86 }; | |
| 87 | |
| 88 typedef std::vector<SimpleDownloadItem*> SimpleItems; | |
| 89 | |
| 90 // Functor passed to std::sort to sort SimpleDownloadItems. | |
| 91 class DownloadComparator { | |
| 92 public: | |
| 93 DownloadComparator(std::string* error_msg, Strings* order_terms) | |
| 94 : error_msg_(error_msg), | |
| 95 order_terms_(order_terms) { | |
| 96 } | |
| 97 | |
| 98 bool operator() (const SimpleDownloadItem* left, | |
| 99 const SimpleDownloadItem* right); | |
| 100 private: | |
| 101 static const char kDash = '-'; | |
| 102 | |
| 103 template <typename FieldType> bool CompareField( | |
| 104 std::string term, | |
| 105 std::string field, | |
| 106 FieldType left, | |
| 107 FieldType right, | |
| 108 bool* matched_term, | |
| 109 bool* cmp) const; | |
| 110 | |
| 111 std::string* error_msg_; | |
| 112 Strings* order_terms_; | |
| 113 // std::sort requires this class to be copyable. | |
| 114 }; | |
| 115 | |
| 116 using download_util::DownloadQuery; | |
| 117 | |
| 118 class DownloadSearch : DownloadQuery { | |
|
cbentzel
2011/10/10 14:35:30
Would it make more sense to have DownloadSearch ow
benjhayden
2011/10/13 14:07:34
The Field classes allowed me to merge DSearch into
| |
| 119 public: | |
| 120 DownloadSearch(const DownloadQuery& query, DownloadItems* items); | |
| 121 ~DownloadSearch() {} | |
| 122 | |
| 123 bool IsWellFormed(std::string* error_msg); | |
| 124 bool Matches(const SimpleDownloadItem& item); | |
| 125 | |
| 126 SimpleItems::const_iterator begin() const { return simple_items_.begin(); } | |
| 127 SimpleItems::const_iterator end() const { return simple_items_.end(); } | |
| 128 | |
| 129 bool ReachedLimit(int num_results) { | |
| 130 return has_limit_ && (num_results >= limit_); | |
| 131 } | |
| 132 | |
| 133 private: | |
| 134 std::string error_msg_; | |
| 135 Strings order_terms_; | |
| 136 SimpleItems simple_items_; | |
| 137 STLElementDeleter<SimpleItems> delete_simple_items_; | |
| 138 Strings query_terms_; | |
| 139 scoped_ptr<icu::RegexPattern> filename_pattern_; | |
| 140 scoped_ptr<icu::RegexPattern> url_pattern_; | |
| 141 DownloadComparator comparator_; | |
| 142 | |
| 143 DISALLOW_COPY_AND_ASSIGN(DownloadSearch); | |
| 144 }; | |
| 145 | |
| 146 base::DictionaryValue* SimpleDownloadItem::ToJSON() const { | |
| 147 base::DictionaryValue* json = new base::DictionaryValue(); | |
| 148 #define FIELD(name, type) \ | |
| 149 json->Set ## type(#name, name()); | |
| 150 #include "content/browser/download/simple_download_item_fields.h" | |
| 151 #undef FIELD | |
| 152 return json; | |
| 153 } | |
| 154 | |
| 155 bool DownloadComparator::operator() ( | |
| 156 const SimpleDownloadItem* left, | |
| 157 const SimpleDownloadItem* right) { | |
| 158 CHECK(left); | |
| 159 CHECK(right); | |
| 160 Strings::iterator order_term, | |
| 161 last_order_term = order_terms_->end(); | |
| 162 for (order_term = order_terms_->begin(); | |
| 163 order_term != last_order_term; ++order_term) { | |
| 164 bool matched_term = false; | |
| 165 bool cmp = false; | |
| 166 #define Integer int | |
| 167 #define Boolean bool | |
| 168 #define String std::string | |
| 169 #define FIELD(name, type) \ | |
| 170 if (CompareField<type>(*order_term, #name, left->name(), right->name(), \ | |
| 171 &matched_term, &cmp)) return cmp; \ | |
| 172 if (matched_term) continue; | |
| 173 #include "content/browser/download/simple_download_item_fields.h" | |
| 174 #undef FIELD | |
| 175 #undef String | |
| 176 #undef Boolean | |
| 177 #undef Integer | |
| 178 *error_msg_ += " " + *order_term; | |
| 179 order_terms_->erase(order_term); | |
| 180 } | |
| 181 CHECK_NE(left->id(), right->id()); | |
| 182 return left->id() < right->id(); | |
| 183 } | |
| 184 | |
| 185 // Return true and set cmp if matched_term and left != right. | |
| 186 template <typename FieldType> | |
| 187 bool DownloadComparator::CompareField( | |
| 188 std::string term, | |
| 189 std::string field, | |
| 190 FieldType left, | |
| 191 FieldType right, | |
| 192 bool* matched_term, | |
| 193 bool* cmp) const { | |
| 194 bool diff = (left != right); | |
| 195 if (term == field) { | |
| 196 *matched_term = true; | |
| 197 if (diff) *cmp = (left < right); | |
| 198 } | |
| 199 if (term == kDash + field) { | |
| 200 *matched_term = true; | |
| 201 if (diff) *cmp = (left > right); | |
| 202 } | |
| 203 return diff && *matched_term; | |
| 204 } | |
| 205 | |
| 206 // NOTE These string constants must match those in | |
| 207 // content/common/extensions/api/extension_api.json | |
| 208 const char SimpleDownloadItem::STATE_IN_PROGRESS[] = "in progress"; | |
| 209 const char SimpleDownloadItem::STATE_COMPLETE[] = "complete"; | |
| 210 const char SimpleDownloadItem::STATE_INTERRUPTED[] = "interrupted"; | |
| 211 const char SimpleDownloadItem::DANGER_SAFE[] = "safe"; | |
| 212 const char SimpleDownloadItem::DANGER_FILE[] = "file"; | |
| 213 const char SimpleDownloadItem::DANGER_URL[] = "url"; | |
| 214 | |
| 215 DownloadSearch::DownloadSearch( | |
| 216 const DownloadQuery& query, DownloadItems* items) | |
| 217 : DownloadQuery(query), | |
| 218 delete_simple_items_(&simple_items_), | |
| 219 comparator_(&error_msg_, &order_terms_) { | |
| 220 if (has_query_) | |
| 221 base::SplitString(query_, ' ', &query_terms_); | |
| 222 // TODO(benjhayden) Split query more intelligently. Quopri? | |
| 223 if (has_filenameRegex_) { | |
| 224 UParseError regex_error; | |
| 225 UErrorCode regex_status = U_ZERO_ERROR; | |
| 226 filename_pattern_.reset(icu::RegexPattern::compile( | |
| 227 icu::UnicodeString::fromUTF8(filenameRegex_), | |
| 228 regex_error, regex_status)); | |
| 229 if (!U_SUCCESS(regex_status)) { | |
| 230 error_msg_ = "bad filenameRegex"; | |
| 231 return; | |
| 232 } | |
| 233 } | |
| 234 if (has_urlRegex_) { | |
| 235 UParseError regex_error; | |
| 236 UErrorCode regex_status = U_ZERO_ERROR; | |
| 237 url_pattern_.reset(icu::RegexPattern::compile( | |
| 238 icu::UnicodeString::fromUTF8(urlRegex_), | |
| 239 regex_error, regex_status)); | |
| 240 if (!U_SUCCESS(regex_status)) { | |
| 241 error_msg_ = "bad urlRegex"; | |
| 242 return; | |
| 243 } | |
| 244 } | |
| 245 for (DownloadItems::const_iterator iter = items->begin(); | |
| 246 iter != items->end(); ++iter) { | |
| 247 if (*iter != NULL) { | |
| 248 if (!filter_func_.is_null() && !filter_func_.Run(**iter)) continue; | |
| 249 simple_items_.push_back(new SimpleDownloadItem(*iter)); | |
| 250 } | |
| 251 } | |
| 252 if (has_orderBy_ && (1 < simple_items_.size())) { | |
| 253 base::SplitString(orderBy_, ' ', &order_terms_); | |
| 254 std::sort(simple_items_.begin(), simple_items_.end(), comparator_); | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 bool DownloadSearch::IsWellFormed(std::string* error_msg) { | |
| 259 if (error_msg != NULL) *error_msg = error_msg_; | |
| 260 return error_msg_.empty(); | |
| 261 } | |
| 262 | |
| 263 bool DownloadSearch::Matches(const SimpleDownloadItem& item) { | |
| 264 #define FIELD(name, unused_type) \ | |
| 265 if (has_ ## name ## _ && (item.name() != name ## _)) return false; | |
| 266 #include "content/browser/download/simple_download_item_fields.h" | |
| 267 #undef FIELD | |
| 268 if (has_state_enum_ && (item.item->state() != state_enum_)) return false; | |
| 269 if (has_danger_enum_ && (item.item->GetDangerType() != danger_enum_)) | |
| 270 return false; | |
| 271 if (has_startedBefore_ && (item.startTime() > startedBefore_)) return false; | |
| 272 if (has_startedAfter_ && (item.startTime() < startedAfter_)) return false; | |
| 273 if (has_endedBefore_ && (item.endTime() > endedBefore_)) return false; | |
| 274 if (has_endedAfter_ && (item.endTime() < endedAfter_)) return false; | |
| 275 if (has_totalBytesGreater_ && (item.totalBytes() < totalBytesGreater_)) | |
| 276 return false; | |
| 277 if (has_totalBytesLess_ && (item.totalBytes() > totalBytesLess_)) | |
| 278 return false; | |
| 279 Strings::const_iterator query_term_iter, | |
| 280 query_term_end = query_terms_.end(); | |
| 281 for (query_term_iter = query_terms_.begin(); | |
| 282 query_term_iter != query_term_end; ++query_term_iter) { | |
| 283 std::string query_term = *query_term_iter; | |
| 284 if ((std::string::npos == item.filename().find(query_term)) && | |
| 285 (std::string::npos == item.url().find(query_term))) { | |
| 286 return false; | |
| 287 } | |
| 288 } | |
| 289 if (filename_pattern_.get() != NULL) { | |
| 290 UErrorCode status = U_ZERO_ERROR; | |
| 291 scoped_ptr<icu::RegexMatcher> filename_matcher(filename_pattern_->matcher( | |
| 292 icu::UnicodeString::fromUTF8(item.filename()), status)); | |
| 293 if (U_FAILURE(status)) { | |
| 294 return false; | |
| 295 } | |
| 296 if (!filename_matcher->find(0, status)) return false; | |
| 297 } | |
| 298 if (url_pattern_.get() != NULL) { | |
| 299 UErrorCode status = U_ZERO_ERROR; | |
| 300 scoped_ptr<icu::RegexMatcher> url_matcher(url_pattern_->matcher( | |
| 301 icu::UnicodeString::fromUTF8(item.url()), status)); | |
| 302 if (U_FAILURE(status)) { | |
| 303 return false; | |
| 304 } | |
| 305 if (!url_matcher->find(0, status)) return false; | |
| 306 } | |
| 307 return true; | |
| 308 } | |
| 309 } // anonymous namespace | |
| 310 | |
| 311 namespace download_util { | |
| 312 | |
| 313 DownloadQuery::DownloadQuery() { | |
| 314 has_state_enum_ = false; | |
| 315 has_danger_enum_ = false; | |
| 316 #define FIELD(name, type) \ | |
| 317 has_ ## name ## _ = false; | |
| 318 #include "content/browser/download/download_query_fields.h" | |
| 319 #undef FIELD | |
| 320 } | |
| 321 | |
| 322 DownloadQuery& DownloadQuery::filter_func(DownloadQuery::FilterType func) { | |
| 323 filter_func_ = func; | |
| 324 return *this; | |
| 325 } | |
| 326 | |
| 327 DownloadQuery& DownloadQuery::state_enum( | |
| 328 DownloadItem::DownloadState stateenum) { | |
| 329 has_state_enum_ = true; | |
| 330 state_enum_ = stateenum; | |
| 331 return *this; | |
| 332 } | |
| 333 | |
| 334 DownloadQuery& DownloadQuery::danger_enum(DownloadItem::DangerType dangerenum) { | |
| 335 has_danger_enum_ = true; | |
| 336 danger_enum_ = dangerenum; | |
| 337 return *this; | |
| 338 } | |
| 339 | |
| 340 bool DownloadQuery::Search( | |
| 341 std::vector<DownloadItem*>* items, | |
| 342 std::string* error_msg, | |
| 343 base::ListValue* results) const { | |
| 344 DownloadSearch search(*this, items); | |
| 345 items->clear(); | |
| 346 if (!search.IsWellFormed(error_msg)) return false; | |
| 347 for (SimpleItems::const_iterator iter = search.begin(); | |
| 348 iter != search.end(); ++iter) { | |
| 349 if (!search.Matches(**iter)) continue; | |
| 350 items->push_back((*iter)->item); | |
| 351 if (results != NULL) results->Append((*iter)->ToJSON()); | |
| 352 if (search.ReachedLimit(items->size())) break; | |
| 353 } | |
| 354 return true; | |
| 355 } | |
| 356 } // namespace download_util | |
| 357 | |
| OLD | NEW |