| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/api/downloads/downloads_api.h" | 5 #include "chrome/browser/extensions/api/downloads/downloads_api.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 |
| 10 #include <algorithm> |
| 9 #include <memory> | 11 #include <memory> |
| 10 #include <set> | 12 #include <set> |
| 11 #include <string> | 13 #include <string> |
| 12 #include <utility> | 14 #include <utility> |
| 13 | 15 |
| 14 #include "base/bind.h" | 16 #include "base/bind.h" |
| 15 #include "base/bind_helpers.h" | 17 #include "base/bind_helpers.h" |
| 16 #include "base/callback.h" | 18 #include "base/callback.h" |
| 17 #include "base/files/file_path.h" | 19 #include "base/files/file_path.h" |
| 18 #include "base/files/file_util.h" | 20 #include "base/files/file_util.h" |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 const char kDangerUrl[] = "url"; | 153 const char kDangerUrl[] = "url"; |
| 152 const char kEndTimeKey[] = "endTime"; | 154 const char kEndTimeKey[] = "endTime"; |
| 153 const char kEndedAfterKey[] = "endedAfter"; | 155 const char kEndedAfterKey[] = "endedAfter"; |
| 154 const char kEndedBeforeKey[] = "endedBefore"; | 156 const char kEndedBeforeKey[] = "endedBefore"; |
| 155 const char kErrorKey[] = "error"; | 157 const char kErrorKey[] = "error"; |
| 156 const char kEstimatedEndTimeKey[] = "estimatedEndTime"; | 158 const char kEstimatedEndTimeKey[] = "estimatedEndTime"; |
| 157 const char kExistsKey[] = "exists"; | 159 const char kExistsKey[] = "exists"; |
| 158 const char kFileSizeKey[] = "fileSize"; | 160 const char kFileSizeKey[] = "fileSize"; |
| 159 const char kFilenameKey[] = "filename"; | 161 const char kFilenameKey[] = "filename"; |
| 160 const char kFilenameRegexKey[] = "filenameRegex"; | 162 const char kFilenameRegexKey[] = "filenameRegex"; |
| 163 const char kFinalUrlKey[] = "finalUrl"; |
| 164 const char kFinalUrlRegexKey[] = "finalUrlRegex"; |
| 161 const char kIdKey[] = "id"; | 165 const char kIdKey[] = "id"; |
| 162 const char kIncognitoKey[] = "incognito"; | 166 const char kIncognitoKey[] = "incognito"; |
| 163 const char kMimeKey[] = "mime"; | 167 const char kMimeKey[] = "mime"; |
| 164 const char kPausedKey[] = "paused"; | 168 const char kPausedKey[] = "paused"; |
| 165 const char kQueryKey[] = "query"; | 169 const char kQueryKey[] = "query"; |
| 166 const char kReferrerUrlKey[] = "referrer"; | 170 const char kReferrerUrlKey[] = "referrer"; |
| 167 const char kStartTimeKey[] = "startTime"; | 171 const char kStartTimeKey[] = "startTime"; |
| 168 const char kStartedAfterKey[] = "startedAfter"; | 172 const char kStartedAfterKey[] = "startedAfter"; |
| 169 const char kStartedBeforeKey[] = "startedBefore"; | 173 const char kStartedBeforeKey[] = "startedBefore"; |
| 170 const char kStateComplete[] = "complete"; | 174 const char kStateComplete[] = "complete"; |
| 171 const char kStateInProgress[] = "in_progress"; | 175 const char kStateInProgress[] = "in_progress"; |
| 172 const char kStateInterrupted[] = "interrupted"; | 176 const char kStateInterrupted[] = "interrupted"; |
| 173 const char kStateKey[] = "state"; | 177 const char kStateKey[] = "state"; |
| 174 const char kTotalBytesGreaterKey[] = "totalBytesGreater"; | 178 const char kTotalBytesGreaterKey[] = "totalBytesGreater"; |
| 175 const char kTotalBytesKey[] = "totalBytes"; | 179 const char kTotalBytesKey[] = "totalBytes"; |
| 176 const char kTotalBytesLessKey[] = "totalBytesLess"; | 180 const char kTotalBytesLessKey[] = "totalBytesLess"; |
| 177 const char kUrlKey[] = "url"; | 181 const char kUrlKey[] = "url"; |
| 178 const char kUrlRegexKey[] = "urlRegex"; | 182 const char kUrlRegexKey[] = "urlRegex"; |
| 179 const char kFinalUrlKey[] = "finalUrl"; | 183 |
| 180 const char kFinalUrlRegexKey[] = "finalUrlRegex"; | 184 // This list must be in order as determined by strcmp. The test |
| 185 // DownloadsApiInternalUnitTest.FilterTypeSorted will verify this. |
| 186 constexpr DownloadQueryFilterTypePair kFilterTypes[] = { |
| 187 {kBytesReceivedKey, DownloadQuery::FILTER_BYTES_RECEIVED}, |
| 188 {kEndTimeKey, DownloadQuery::FILTER_END_TIME}, |
| 189 {kEndedAfterKey, DownloadQuery::FILTER_ENDED_AFTER}, |
| 190 {kEndedBeforeKey, DownloadQuery::FILTER_ENDED_BEFORE}, |
| 191 {kExistsKey, DownloadQuery::FILTER_EXISTS}, |
| 192 {kFilenameKey, DownloadQuery::FILTER_FILENAME}, |
| 193 {kFilenameRegexKey, DownloadQuery::FILTER_FILENAME_REGEX}, |
| 194 {kFinalUrlKey, DownloadQuery::FILTER_URL}, |
| 195 {kFinalUrlRegexKey, DownloadQuery::FILTER_URL_REGEX}, |
| 196 {kMimeKey, DownloadQuery::FILTER_MIME}, |
| 197 {kPausedKey, DownloadQuery::FILTER_PAUSED}, |
| 198 {kQueryKey, DownloadQuery::FILTER_QUERY}, |
| 199 {kStartTimeKey, DownloadQuery::FILTER_START_TIME}, |
| 200 {kStartedAfterKey, DownloadQuery::FILTER_STARTED_AFTER}, |
| 201 {kStartedBeforeKey, DownloadQuery::FILTER_STARTED_BEFORE}, |
| 202 {kTotalBytesKey, DownloadQuery::FILTER_TOTAL_BYTES}, |
| 203 {kTotalBytesGreaterKey, DownloadQuery::FILTER_TOTAL_BYTES_GREATER}, |
| 204 {kTotalBytesLessKey, DownloadQuery::FILTER_TOTAL_BYTES_LESS}, |
| 205 {kUrlKey, DownloadQuery::FILTER_ORIGINAL_URL}, |
| 206 {kUrlRegexKey, DownloadQuery::FILTER_ORIGINAL_URL_REGEX}, |
| 207 }; |
| 208 |
| 209 // This list must be in order as determined by strcmp. The test |
| 210 // DownloadsApiInternalUnitTest.SortTypeSorted will verify this. |
| 211 constexpr DownloadQuerySortTypePair kSortTypes[] = { |
| 212 {kBytesReceivedKey, DownloadQuery::SORT_BYTES_RECEIVED}, |
| 213 {kDangerKey, DownloadQuery::SORT_DANGER}, |
| 214 {kEndTimeKey, DownloadQuery::SORT_END_TIME}, |
| 215 {kExistsKey, DownloadQuery::SORT_EXISTS}, |
| 216 {kFilenameKey, DownloadQuery::SORT_FILENAME}, |
| 217 {kFinalUrlKey, DownloadQuery::SORT_URL}, |
| 218 {kMimeKey, DownloadQuery::SORT_MIME}, |
| 219 {kPausedKey, DownloadQuery::SORT_PAUSED}, |
| 220 {kStartTimeKey, DownloadQuery::SORT_START_TIME}, |
| 221 {kStateKey, DownloadQuery::SORT_STATE}, |
| 222 {kTotalBytesKey, DownloadQuery::SORT_TOTAL_BYTES}, |
| 223 {kUrlKey, DownloadQuery::SORT_ORIGINAL_URL}, |
| 224 }; |
| 181 | 225 |
| 182 // Note: Any change to the danger type strings, should be accompanied by a | 226 // Note: Any change to the danger type strings, should be accompanied by a |
| 183 // corresponding change to downloads.json. | 227 // corresponding change to downloads.json. |
| 184 const char* const kDangerStrings[] = { | 228 const char* const kDangerStrings[] = { |
| 185 kDangerSafe, | 229 kDangerSafe, |
| 186 kDangerFile, | 230 kDangerFile, |
| 187 kDangerUrl, | 231 kDangerUrl, |
| 188 kDangerContent, | 232 kDangerContent, |
| 189 kDangerSafe, | 233 kDangerSafe, |
| 190 kDangerUncommon, | 234 kDangerUncommon, |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 IconLoader::IconSize IconLoaderSizeFromPixelSize(int pixel_size) { | 399 IconLoader::IconSize IconLoaderSizeFromPixelSize(int pixel_size) { |
| 356 switch (pixel_size) { | 400 switch (pixel_size) { |
| 357 case 16: return IconLoader::SMALL; | 401 case 16: return IconLoader::SMALL; |
| 358 case 32: return IconLoader::NORMAL; | 402 case 32: return IconLoader::NORMAL; |
| 359 default: | 403 default: |
| 360 NOTREACHED(); | 404 NOTREACHED(); |
| 361 return IconLoader::NORMAL; | 405 return IconLoader::NORMAL; |
| 362 } | 406 } |
| 363 } | 407 } |
| 364 | 408 |
| 365 typedef base::hash_map<std::string, DownloadQuery::FilterType> FilterTypeMap; | |
| 366 | |
| 367 void InitFilterTypeMap(FilterTypeMap* filter_types_ptr) { | |
| 368 FilterTypeMap& filter_types = *filter_types_ptr; | |
| 369 filter_types[kBytesReceivedKey] = DownloadQuery::FILTER_BYTES_RECEIVED; | |
| 370 filter_types[kExistsKey] = DownloadQuery::FILTER_EXISTS; | |
| 371 filter_types[kFilenameKey] = DownloadQuery::FILTER_FILENAME; | |
| 372 filter_types[kFilenameRegexKey] = DownloadQuery::FILTER_FILENAME_REGEX; | |
| 373 filter_types[kMimeKey] = DownloadQuery::FILTER_MIME; | |
| 374 filter_types[kPausedKey] = DownloadQuery::FILTER_PAUSED; | |
| 375 filter_types[kQueryKey] = DownloadQuery::FILTER_QUERY; | |
| 376 filter_types[kEndedAfterKey] = DownloadQuery::FILTER_ENDED_AFTER; | |
| 377 filter_types[kEndedBeforeKey] = DownloadQuery::FILTER_ENDED_BEFORE; | |
| 378 filter_types[kEndTimeKey] = DownloadQuery::FILTER_END_TIME; | |
| 379 filter_types[kStartedAfterKey] = DownloadQuery::FILTER_STARTED_AFTER; | |
| 380 filter_types[kStartedBeforeKey] = DownloadQuery::FILTER_STARTED_BEFORE; | |
| 381 filter_types[kStartTimeKey] = DownloadQuery::FILTER_START_TIME; | |
| 382 filter_types[kTotalBytesKey] = DownloadQuery::FILTER_TOTAL_BYTES; | |
| 383 filter_types[kTotalBytesGreaterKey] = | |
| 384 DownloadQuery::FILTER_TOTAL_BYTES_GREATER; | |
| 385 filter_types[kTotalBytesLessKey] = DownloadQuery::FILTER_TOTAL_BYTES_LESS; | |
| 386 filter_types[kUrlKey] = DownloadQuery::FILTER_ORIGINAL_URL; | |
| 387 filter_types[kUrlRegexKey] = DownloadQuery::FILTER_ORIGINAL_URL_REGEX; | |
| 388 filter_types[kFinalUrlKey] = DownloadQuery::FILTER_URL; | |
| 389 filter_types[kFinalUrlRegexKey] = DownloadQuery::FILTER_URL_REGEX; | |
| 390 } | |
| 391 | |
| 392 typedef base::hash_map<std::string, DownloadQuery::SortType> SortTypeMap; | |
| 393 | |
| 394 void InitSortTypeMap(SortTypeMap* sorter_types_ptr) { | |
| 395 SortTypeMap& sorter_types = *sorter_types_ptr; | |
| 396 sorter_types[kBytesReceivedKey] = DownloadQuery::SORT_BYTES_RECEIVED; | |
| 397 sorter_types[kDangerKey] = DownloadQuery::SORT_DANGER; | |
| 398 sorter_types[kEndTimeKey] = DownloadQuery::SORT_END_TIME; | |
| 399 sorter_types[kExistsKey] = DownloadQuery::SORT_EXISTS; | |
| 400 sorter_types[kFilenameKey] = DownloadQuery::SORT_FILENAME; | |
| 401 sorter_types[kMimeKey] = DownloadQuery::SORT_MIME; | |
| 402 sorter_types[kPausedKey] = DownloadQuery::SORT_PAUSED; | |
| 403 sorter_types[kStartTimeKey] = DownloadQuery::SORT_START_TIME; | |
| 404 sorter_types[kStateKey] = DownloadQuery::SORT_STATE; | |
| 405 sorter_types[kTotalBytesKey] = DownloadQuery::SORT_TOTAL_BYTES; | |
| 406 sorter_types[kUrlKey] = DownloadQuery::SORT_ORIGINAL_URL; | |
| 407 sorter_types[kFinalUrlKey] = DownloadQuery::SORT_URL; | |
| 408 } | |
| 409 | |
| 410 bool IsNotTemporaryDownloadFilter(const DownloadItem& download_item) { | 409 bool IsNotTemporaryDownloadFilter(const DownloadItem& download_item) { |
| 411 return !download_item.IsTemporary(); | 410 return !download_item.IsTemporary(); |
| 412 } | 411 } |
| 413 | 412 |
| 414 // Set |manager| to the on-record DownloadManager, and |incognito_manager| to | 413 // Set |manager| to the on-record DownloadManager, and |incognito_manager| to |
| 415 // the off-record DownloadManager if one exists and is requested via | 414 // the off-record DownloadManager if one exists and is requested via |
| 416 // |include_incognito|. This should work regardless of whether |profile| is | 415 // |include_incognito|. This should work regardless of whether |profile| is |
| 417 // original or incognito. | 416 // original or incognito. |
| 418 void GetManagers(content::BrowserContext* context, | 417 void GetManagers(content::BrowserContext* context, |
| 419 bool include_incognito, | 418 bool include_incognito, |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 void RecordApiFunctions(DownloadsFunctionName function) { | 468 void RecordApiFunctions(DownloadsFunctionName function) { |
| 470 UMA_HISTOGRAM_ENUMERATION("Download.ApiFunctions", | 469 UMA_HISTOGRAM_ENUMERATION("Download.ApiFunctions", |
| 471 function, | 470 function, |
| 472 DOWNLOADS_FUNCTION_LAST); | 471 DOWNLOADS_FUNCTION_LAST); |
| 473 } | 472 } |
| 474 | 473 |
| 475 void CompileDownloadQueryOrderBy( | 474 void CompileDownloadQueryOrderBy( |
| 476 const std::vector<std::string>& order_by_strs, | 475 const std::vector<std::string>& order_by_strs, |
| 477 std::string* error, | 476 std::string* error, |
| 478 DownloadQuery* query) { | 477 DownloadQuery* query) { |
| 479 // TODO(benjhayden): Consider switching from LazyInstance to explicit string | |
| 480 // comparisons. | |
| 481 static base::LazyInstance<SortTypeMap>::DestructorAtExit sorter_types = | |
| 482 LAZY_INSTANCE_INITIALIZER; | |
| 483 if (sorter_types.Get().empty()) | |
| 484 InitSortTypeMap(sorter_types.Pointer()); | |
| 485 | |
| 486 for (std::vector<std::string>::const_iterator iter = order_by_strs.begin(); | 478 for (std::vector<std::string>::const_iterator iter = order_by_strs.begin(); |
| 487 iter != order_by_strs.end(); ++iter) { | 479 iter != order_by_strs.end(); ++iter) { |
| 488 std::string term_str = *iter; | 480 std::string term_str = *iter; |
| 489 if (term_str.empty()) | 481 if (term_str.empty()) |
| 490 continue; | 482 continue; |
| 491 DownloadQuery::SortDirection direction = DownloadQuery::ASCENDING; | 483 DownloadQuery::SortDirection direction = DownloadQuery::ASCENDING; |
| 492 if (term_str[0] == '-') { | 484 if (term_str[0] == '-') { |
| 493 direction = DownloadQuery::DESCENDING; | 485 direction = DownloadQuery::DESCENDING; |
| 494 term_str = term_str.substr(1); | 486 term_str = term_str.substr(1); |
| 495 } | 487 } |
| 496 SortTypeMap::const_iterator sorter_type = | 488 const DownloadQuerySortTypePair* found_sort = |
| 497 sorter_types.Get().find(term_str); | 489 FindDownloadSortTypeByString(term_str.c_str()); |
| 498 if (sorter_type == sorter_types.Get().end()) { | 490 if (!found_sort) { |
| 499 *error = errors::kInvalidOrderBy; | 491 *error = errors::kInvalidOrderBy; |
| 500 return; | 492 return; |
| 501 } | 493 } |
| 502 query->AddSorter(sorter_type->second, direction); | 494 query->AddSorter(found_sort->second, direction); |
| 503 } | 495 } |
| 504 } | 496 } |
| 505 | 497 |
| 506 void RunDownloadQuery( | 498 void RunDownloadQuery( |
| 507 const downloads::DownloadQuery& query_in, | 499 const downloads::DownloadQuery& query_in, |
| 508 DownloadManager* manager, | 500 DownloadManager* manager, |
| 509 DownloadManager* incognito_manager, | 501 DownloadManager* incognito_manager, |
| 510 std::string* error, | 502 std::string* error, |
| 511 DownloadQuery::DownloadVector* results) { | 503 DownloadQuery::DownloadVector* results) { |
| 512 // TODO(benjhayden): Consider switching from LazyInstance to explicit string | |
| 513 // comparisons. | |
| 514 static base::LazyInstance<FilterTypeMap>::DestructorAtExit filter_types = | |
| 515 LAZY_INSTANCE_INITIALIZER; | |
| 516 if (filter_types.Get().empty()) | |
| 517 InitFilterTypeMap(filter_types.Pointer()); | |
| 518 | |
| 519 DownloadQuery query_out; | 504 DownloadQuery query_out; |
| 520 | 505 |
| 521 size_t limit = 1000; | 506 size_t limit = 1000; |
| 522 if (query_in.limit.get()) { | 507 if (query_in.limit.get()) { |
| 523 if (*query_in.limit < 0) { | 508 if (*query_in.limit < 0) { |
| 524 *error = errors::kInvalidQueryLimit; | 509 *error = errors::kInvalidQueryLimit; |
| 525 return; | 510 return; |
| 526 } | 511 } |
| 527 limit = *query_in.limit; | 512 limit = *query_in.limit; |
| 528 } | 513 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 552 } | 537 } |
| 553 if (query_in.order_by.get()) { | 538 if (query_in.order_by.get()) { |
| 554 CompileDownloadQueryOrderBy(*query_in.order_by, error, &query_out); | 539 CompileDownloadQueryOrderBy(*query_in.order_by, error, &query_out); |
| 555 if (!error->empty()) | 540 if (!error->empty()) |
| 556 return; | 541 return; |
| 557 } | 542 } |
| 558 | 543 |
| 559 std::unique_ptr<base::DictionaryValue> query_in_value(query_in.ToValue()); | 544 std::unique_ptr<base::DictionaryValue> query_in_value(query_in.ToValue()); |
| 560 for (base::DictionaryValue::Iterator query_json_field(*query_in_value); | 545 for (base::DictionaryValue::Iterator query_json_field(*query_in_value); |
| 561 !query_json_field.IsAtEnd(); query_json_field.Advance()) { | 546 !query_json_field.IsAtEnd(); query_json_field.Advance()) { |
| 562 FilterTypeMap::const_iterator filter_type = | 547 const DownloadQueryFilterTypePair* found_filter = |
| 563 filter_types.Get().find(query_json_field.key()); | 548 FindDownloadFilterTypeByString(query_json_field.key().c_str()); |
| 564 if (filter_type != filter_types.Get().end()) { | 549 if (found_filter) { |
| 565 if (!query_out.AddFilter(filter_type->second, query_json_field.value())) { | 550 if (!query_out.AddFilter(found_filter->second, |
| 551 query_json_field.value())) { |
| 566 *error = errors::kInvalidFilter; | 552 *error = errors::kInvalidFilter; |
| 567 return; | 553 return; |
| 568 } | 554 } |
| 569 } | 555 } |
| 570 } | 556 } |
| 571 | 557 |
| 572 DownloadQuery::DownloadVector all_items; | 558 DownloadQuery::DownloadVector all_items; |
| 573 if (query_in.id.get()) { | 559 if (query_in.id.get()) { |
| 574 DownloadItem* download_item = manager->GetDownload(*query_in.id); | 560 DownloadItem* download_item = manager->GetDownload(*query_in.id); |
| 575 if (!download_item && incognito_manager) | 561 if (!download_item && incognito_manager) |
| (...skipping 1384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1960 if (!manager) | 1946 if (!manager) |
| 1961 return; | 1947 return; |
| 1962 base::Time now(base::Time::Now()); | 1948 base::Time now(base::Time::Now()); |
| 1963 int delta = now.ToTimeT() - last_checked_removal_.ToTimeT(); | 1949 int delta = now.ToTimeT() - last_checked_removal_.ToTimeT(); |
| 1964 if (delta <= kFileExistenceRateLimitSeconds) | 1950 if (delta <= kFileExistenceRateLimitSeconds) |
| 1965 return; | 1951 return; |
| 1966 last_checked_removal_ = now; | 1952 last_checked_removal_ = now; |
| 1967 manager->CheckForHistoryFilesRemoval(); | 1953 manager->CheckForHistoryFilesRemoval(); |
| 1968 } | 1954 } |
| 1969 | 1955 |
| 1956 const DownloadQueryFilterTypePair* FindDownloadFilterTypeByString( |
| 1957 const char* key) { |
| 1958 struct FilterTypeKeyLess { |
| 1959 bool operator()(const DownloadQueryFilterTypePair& a, const char* b) const { |
| 1960 return strcmp(a.first, b) < 0; |
| 1961 } |
| 1962 }; |
| 1963 |
| 1964 const DownloadQueryFilterTypePair* found = |
| 1965 std::lower_bound(std::begin(kFilterTypes), std::end(kFilterTypes), key, |
| 1966 FilterTypeKeyLess()); |
| 1967 if (found == std::end(kFilterTypes) || strcmp(key, found->first) != 0) |
| 1968 return nullptr; |
| 1969 return found; |
| 1970 } |
| 1971 |
| 1972 const DownloadQuerySortTypePair* FindDownloadSortTypeByString(const char* key) { |
| 1973 struct SortTypeKeyLess { |
| 1974 bool operator()(const DownloadQuerySortTypePair& a, const char* b) const { |
| 1975 return strcmp(a.first, b) < 0; |
| 1976 } |
| 1977 }; |
| 1978 |
| 1979 const DownloadQuerySortTypePair* found = std::lower_bound( |
| 1980 std::begin(kSortTypes), std::end(kSortTypes), key, SortTypeKeyLess()); |
| 1981 if (found == std::end(kSortTypes) || strcmp(key, found->first) != 0) |
| 1982 return nullptr; |
| 1983 return found; |
| 1984 } |
| 1985 |
| 1986 const DownloadQueryFilterTypePair* DownloadQueryFilterTypeBeginForTest() { |
| 1987 return std::begin(kFilterTypes); |
| 1988 } |
| 1989 |
| 1990 const DownloadQueryFilterTypePair* DownloadQueryFilterTypeEndForTest() { |
| 1991 return std::end(kFilterTypes); |
| 1992 } |
| 1993 |
| 1994 const DownloadQuerySortTypePair* DownloadQuerySortTypeBeginForTest() { |
| 1995 return std::begin(kSortTypes); |
| 1996 } |
| 1997 |
| 1998 const DownloadQuerySortTypePair* DownloadQuerySortTypeEndForTest() { |
| 1999 return std::end(kSortTypes); |
| 2000 } |
| 2001 |
| 1970 } // namespace extensions | 2002 } // namespace extensions |
| OLD | NEW |