Home | History | Annotate | Download | only in downloads
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
      6 
      7 #include <algorithm>
      8 #include <cctype>
      9 #include <iterator>
     10 #include <set>
     11 #include <string>
     12 
     13 #include "base/basictypes.h"
     14 #include "base/bind.h"
     15 #include "base/bind_helpers.h"
     16 #include "base/callback.h"
     17 #include "base/file_util.h"
     18 #include "base/files/file_path.h"
     19 #include "base/json/json_writer.h"
     20 #include "base/lazy_instance.h"
     21 #include "base/logging.h"
     22 #include "base/memory/weak_ptr.h"
     23 #include "base/metrics/histogram.h"
     24 #include "base/stl_util.h"
     25 #include "base/strings/string16.h"
     26 #include "base/strings/string_split.h"
     27 #include "base/strings/string_util.h"
     28 #include "base/strings/stringprintf.h"
     29 #include "base/values.h"
     30 #include "chrome/browser/browser_process.h"
     31 #include "chrome/browser/chrome_notification_types.h"
     32 #include "chrome/browser/download/download_danger_prompt.h"
     33 #include "chrome/browser/download/download_file_icon_extractor.h"
     34 #include "chrome/browser/download/download_prefs.h"
     35 #include "chrome/browser/download/download_query.h"
     36 #include "chrome/browser/download/download_service.h"
     37 #include "chrome/browser/download/download_service_factory.h"
     38 #include "chrome/browser/download/download_shelf.h"
     39 #include "chrome/browser/download/download_stats.h"
     40 #include "chrome/browser/download/drag_download_item.h"
     41 #include "chrome/browser/extensions/extension_function_dispatcher.h"
     42 #include "chrome/browser/extensions/extension_prefs.h"
     43 #include "chrome/browser/extensions/extension_service.h"
     44 #include "chrome/browser/extensions/extension_system.h"
     45 #include "chrome/browser/extensions/extension_warning_service.h"
     46 #include "chrome/browser/extensions/extension_warning_set.h"
     47 #include "chrome/browser/icon_loader.h"
     48 #include "chrome/browser/icon_manager.h"
     49 #include "chrome/browser/platform_util.h"
     50 #include "chrome/browser/profiles/profile.h"
     51 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
     52 #include "chrome/browser/ui/browser.h"
     53 #include "chrome/browser/ui/browser_list.h"
     54 #include "chrome/browser/ui/browser_window.h"
     55 #include "chrome/common/cancelable_task_tracker.h"
     56 #include "chrome/common/extensions/api/downloads.h"
     57 #include "components/web_modal/web_contents_modal_dialog_manager.h"
     58 #include "content/public/browser/download_interrupt_reasons.h"
     59 #include "content/public/browser/download_item.h"
     60 #include "content/public/browser/download_save_info.h"
     61 #include "content/public/browser/download_url_parameters.h"
     62 #include "content/public/browser/notification_details.h"
     63 #include "content/public/browser/notification_service.h"
     64 #include "content/public/browser/notification_source.h"
     65 #include "content/public/browser/render_process_host.h"
     66 #include "content/public/browser/render_view_host.h"
     67 #include "content/public/browser/resource_context.h"
     68 #include "content/public/browser/resource_dispatcher_host.h"
     69 #include "content/public/browser/web_contents.h"
     70 #include "content/public/browser/web_contents.h"
     71 #include "content/public/browser/web_contents_view.h"
     72 #include "content/public/browser/web_contents_view.h"
     73 #include "extensions/browser/event_router.h"
     74 #include "extensions/common/extension.h"
     75 #include "extensions/common/permissions/permissions_data.h"
     76 #include "net/base/load_flags.h"
     77 #include "net/base/net_util.h"
     78 #include "net/http/http_util.h"
     79 #include "net/url_request/url_request.h"
     80 #include "third_party/skia/include/core/SkBitmap.h"
     81 #include "ui/base/webui/web_ui_util.h"
     82 
     83 using content::BrowserContext;
     84 using content::BrowserThread;
     85 using content::DownloadItem;
     86 using content::DownloadManager;
     87 
     88 namespace download_extension_errors {
     89 
     90 const char kEmptyFile[] = "Filename not yet determined";
     91 const char kFileAlreadyDeleted[] = "Download file already deleted";
     92 const char kIconNotFound[] = "Icon not found";
     93 const char kInvalidDangerType[] = "Invalid danger type";
     94 const char kInvalidFilename[] = "Invalid filename";
     95 const char kInvalidFilter[] = "Invalid query filter";
     96 const char kInvalidHeader[] = "Invalid request header";
     97 const char kInvalidId[] = "Invalid downloadId";
     98 const char kInvalidOrderBy[] = "Invalid orderBy field";
     99 const char kInvalidQueryLimit[] = "Invalid query limit";
    100 const char kInvalidState[] = "Invalid state";
    101 const char kInvalidURL[] = "Invalid URL";
    102 const char kInvisibleContext[] = "Javascript execution context is not visible "
    103   "(tab, window, popup bubble)";
    104 const char kNotComplete[] = "Download must be complete";
    105 const char kNotDangerous[] = "Download must be dangerous";
    106 const char kNotInProgress[] = "Download must be in progress";
    107 const char kNotResumable[] = "DownloadItem.canResume must be true";
    108 const char kOpenPermission[] = "The \"downloads.open\" permission is required";
    109 const char kShelfDisabled[] = "Another extension has disabled the shelf";
    110 const char kShelfPermission[] = "downloads.setShelfEnabled requires the "
    111   "\"downloads.shelf\" permission";
    112 const char kTooManyListeners[] = "Each extension may have at most one "
    113   "onDeterminingFilename listener between all of its renderer execution "
    114   "contexts.";
    115 const char kUnexpectedDeterminer[] = "Unexpected determineFilename call";
    116 
    117 }  // namespace download_extension_errors
    118 
    119 namespace errors = download_extension_errors;
    120 
    121 namespace {
    122 
    123 namespace downloads = extensions::api::downloads;
    124 
    125 // Default icon size for getFileIcon() in pixels.
    126 const int  kDefaultIconSize = 32;
    127 
    128 // Parameter keys
    129 const char kByExtensionIdKey[] = "byExtensionId";
    130 const char kByExtensionNameKey[] = "byExtensionName";
    131 const char kBytesReceivedKey[] = "bytesReceived";
    132 const char kCanResumeKey[] = "canResume";
    133 const char kDangerAccepted[] = "accepted";
    134 const char kDangerContent[] = "content";
    135 const char kDangerFile[] = "file";
    136 const char kDangerHost[] = "host";
    137 const char kDangerKey[] = "danger";
    138 const char kDangerSafe[] = "safe";
    139 const char kDangerUncommon[] = "uncommon";
    140 const char kDangerUnwanted[] = "unwanted";
    141 const char kDangerUrl[] = "url";
    142 const char kEndTimeKey[] = "endTime";
    143 const char kEndedAfterKey[] = "endedAfter";
    144 const char kEndedBeforeKey[] = "endedBefore";
    145 const char kErrorKey[] = "error";
    146 const char kEstimatedEndTimeKey[] = "estimatedEndTime";
    147 const char kExistsKey[] = "exists";
    148 const char kFileSizeKey[] = "fileSize";
    149 const char kFilenameKey[] = "filename";
    150 const char kFilenameRegexKey[] = "filenameRegex";
    151 const char kIdKey[] = "id";
    152 const char kIncognitoKey[] = "incognito";
    153 const char kMimeKey[] = "mime";
    154 const char kPausedKey[] = "paused";
    155 const char kQueryKey[] = "query";
    156 const char kReferrerUrlKey[] = "referrer";
    157 const char kStartTimeKey[] = "startTime";
    158 const char kStartedAfterKey[] = "startedAfter";
    159 const char kStartedBeforeKey[] = "startedBefore";
    160 const char kStateComplete[] = "complete";
    161 const char kStateInProgress[] = "in_progress";
    162 const char kStateInterrupted[] = "interrupted";
    163 const char kStateKey[] = "state";
    164 const char kTotalBytesGreaterKey[] = "totalBytesGreater";
    165 const char kTotalBytesKey[] = "totalBytes";
    166 const char kTotalBytesLessKey[] = "totalBytesLess";
    167 const char kUrlKey[] = "url";
    168 const char kUrlRegexKey[] = "urlRegex";
    169 
    170 // Note: Any change to the danger type strings, should be accompanied by a
    171 // corresponding change to downloads.json.
    172 const char* kDangerStrings[] = {
    173   kDangerSafe,
    174   kDangerFile,
    175   kDangerUrl,
    176   kDangerContent,
    177   kDangerSafe,
    178   kDangerUncommon,
    179   kDangerAccepted,
    180   kDangerHost,
    181   kDangerUnwanted
    182 };
    183 COMPILE_ASSERT(arraysize(kDangerStrings) == content::DOWNLOAD_DANGER_TYPE_MAX,
    184                download_danger_type_enum_changed);
    185 
    186 // Note: Any change to the state strings, should be accompanied by a
    187 // corresponding change to downloads.json.
    188 const char* kStateStrings[] = {
    189   kStateInProgress,
    190   kStateComplete,
    191   kStateInterrupted,
    192   kStateInterrupted,
    193 };
    194 COMPILE_ASSERT(arraysize(kStateStrings) == DownloadItem::MAX_DOWNLOAD_STATE,
    195                download_item_state_enum_changed);
    196 
    197 const char* DangerString(content::DownloadDangerType danger) {
    198   DCHECK(danger >= 0);
    199   DCHECK(danger < static_cast<content::DownloadDangerType>(
    200       arraysize(kDangerStrings)));
    201   if (danger < 0 || danger >= static_cast<content::DownloadDangerType>(
    202       arraysize(kDangerStrings)))
    203     return "";
    204   return kDangerStrings[danger];
    205 }
    206 
    207 content::DownloadDangerType DangerEnumFromString(const std::string& danger) {
    208   for (size_t i = 0; i < arraysize(kDangerStrings); ++i) {
    209     if (danger == kDangerStrings[i])
    210       return static_cast<content::DownloadDangerType>(i);
    211   }
    212   return content::DOWNLOAD_DANGER_TYPE_MAX;
    213 }
    214 
    215 const char* StateString(DownloadItem::DownloadState state) {
    216   DCHECK(state >= 0);
    217   DCHECK(state < static_cast<DownloadItem::DownloadState>(
    218       arraysize(kStateStrings)));
    219   if (state < 0 || state >= static_cast<DownloadItem::DownloadState>(
    220       arraysize(kStateStrings)))
    221     return "";
    222   return kStateStrings[state];
    223 }
    224 
    225 DownloadItem::DownloadState StateEnumFromString(const std::string& state) {
    226   for (size_t i = 0; i < arraysize(kStateStrings); ++i) {
    227     if ((kStateStrings[i] != NULL) && (state == kStateStrings[i]))
    228       return static_cast<DownloadItem::DownloadState>(i);
    229   }
    230   return DownloadItem::MAX_DOWNLOAD_STATE;
    231 }
    232 
    233 std::string TimeToISO8601(const base::Time& t) {
    234   base::Time::Exploded exploded;
    235   t.UTCExplode(&exploded);
    236   return base::StringPrintf(
    237       "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", exploded.year, exploded.month,
    238       exploded.day_of_month, exploded.hour, exploded.minute, exploded.second,
    239       exploded.millisecond);
    240 }
    241 
    242 scoped_ptr<base::DictionaryValue> DownloadItemToJSON(
    243     DownloadItem* download_item,
    244     Profile* profile) {
    245   base::DictionaryValue* json = new base::DictionaryValue();
    246   json->SetBoolean(kExistsKey, !download_item->GetFileExternallyRemoved());
    247   json->SetInteger(kIdKey, download_item->GetId());
    248   const GURL& url = download_item->GetOriginalUrl();
    249   json->SetString(kUrlKey, (url.is_valid() ? url.spec() : std::string()));
    250   const GURL& referrer = download_item->GetReferrerUrl();
    251   json->SetString(kReferrerUrlKey, (referrer.is_valid() ? referrer.spec()
    252                                                         : std::string()));
    253   json->SetString(kFilenameKey,
    254                   download_item->GetTargetFilePath().LossyDisplayName());
    255   json->SetString(kDangerKey, DangerString(download_item->GetDangerType()));
    256   json->SetString(kStateKey, StateString(download_item->GetState()));
    257   json->SetBoolean(kCanResumeKey, download_item->CanResume());
    258   json->SetBoolean(kPausedKey, download_item->IsPaused());
    259   json->SetString(kMimeKey, download_item->GetMimeType());
    260   json->SetString(kStartTimeKey, TimeToISO8601(download_item->GetStartTime()));
    261   json->SetInteger(kBytesReceivedKey, download_item->GetReceivedBytes());
    262   json->SetInteger(kTotalBytesKey, download_item->GetTotalBytes());
    263   json->SetBoolean(kIncognitoKey, profile->IsOffTheRecord());
    264   if (download_item->GetState() == DownloadItem::INTERRUPTED) {
    265     json->SetString(kErrorKey, content::InterruptReasonDebugString(
    266         download_item->GetLastReason()));
    267   } else if (download_item->GetState() == DownloadItem::CANCELLED) {
    268     json->SetString(kErrorKey, content::InterruptReasonDebugString(
    269         content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED));
    270   }
    271   if (!download_item->GetEndTime().is_null())
    272     json->SetString(kEndTimeKey, TimeToISO8601(download_item->GetEndTime()));
    273   base::TimeDelta time_remaining;
    274   if (download_item->TimeRemaining(&time_remaining)) {
    275     base::Time now = base::Time::Now();
    276     json->SetString(kEstimatedEndTimeKey, TimeToISO8601(now + time_remaining));
    277   }
    278   DownloadedByExtension* by_ext = DownloadedByExtension::Get(download_item);
    279   if (by_ext) {
    280     json->SetString(kByExtensionIdKey, by_ext->id());
    281     json->SetString(kByExtensionNameKey, by_ext->name());
    282     // Lookup the extension's current name() in case the user changed their
    283     // language. This won't work if the extension was uninstalled, so the name
    284     // might be the wrong language.
    285     bool include_disabled = true;
    286     const extensions::Extension* extension = extensions::ExtensionSystem::Get(
    287         profile)->extension_service()->GetExtensionById(
    288             by_ext->id(), include_disabled);
    289     if (extension)
    290       json->SetString(kByExtensionNameKey, extension->name());
    291   }
    292   // TODO(benjhayden): Implement fileSize.
    293   json->SetInteger(kFileSizeKey, download_item->GetTotalBytes());
    294   return scoped_ptr<base::DictionaryValue>(json);
    295 }
    296 
    297 class DownloadFileIconExtractorImpl : public DownloadFileIconExtractor {
    298  public:
    299   DownloadFileIconExtractorImpl() {}
    300 
    301   virtual ~DownloadFileIconExtractorImpl() {}
    302 
    303   virtual bool ExtractIconURLForPath(const base::FilePath& path,
    304                                      IconLoader::IconSize icon_size,
    305                                      IconURLCallback callback) OVERRIDE;
    306  private:
    307   void OnIconLoadComplete(gfx::Image* icon);
    308 
    309   CancelableTaskTracker cancelable_task_tracker_;
    310   IconURLCallback callback_;
    311 };
    312 
    313 bool DownloadFileIconExtractorImpl::ExtractIconURLForPath(
    314     const base::FilePath& path,
    315     IconLoader::IconSize icon_size,
    316     IconURLCallback callback) {
    317   callback_ = callback;
    318   IconManager* im = g_browser_process->icon_manager();
    319   // The contents of the file at |path| may have changed since a previous
    320   // request, in which case the associated icon may also have changed.
    321   // Therefore, always call LoadIcon instead of attempting a LookupIcon.
    322   im->LoadIcon(path,
    323                icon_size,
    324                base::Bind(&DownloadFileIconExtractorImpl::OnIconLoadComplete,
    325                           base::Unretained(this)),
    326                &cancelable_task_tracker_);
    327   return true;
    328 }
    329 
    330 void DownloadFileIconExtractorImpl::OnIconLoadComplete(gfx::Image* icon) {
    331   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    332   std::string url;
    333   if (icon)
    334     url = webui::GetBitmapDataUrl(icon->AsBitmap());
    335   callback_.Run(url);
    336 }
    337 
    338 IconLoader::IconSize IconLoaderSizeFromPixelSize(int pixel_size) {
    339   switch (pixel_size) {
    340     case 16: return IconLoader::SMALL;
    341     case 32: return IconLoader::NORMAL;
    342     default:
    343       NOTREACHED();
    344       return IconLoader::NORMAL;
    345   }
    346 }
    347 
    348 typedef base::hash_map<std::string, DownloadQuery::FilterType> FilterTypeMap;
    349 
    350 void InitFilterTypeMap(FilterTypeMap& filter_types) {
    351   filter_types[kBytesReceivedKey] = DownloadQuery::FILTER_BYTES_RECEIVED;
    352   filter_types[kExistsKey] = DownloadQuery::FILTER_EXISTS;
    353   filter_types[kFilenameKey] = DownloadQuery::FILTER_FILENAME;
    354   filter_types[kFilenameRegexKey] = DownloadQuery::FILTER_FILENAME_REGEX;
    355   filter_types[kMimeKey] = DownloadQuery::FILTER_MIME;
    356   filter_types[kPausedKey] = DownloadQuery::FILTER_PAUSED;
    357   filter_types[kQueryKey] = DownloadQuery::FILTER_QUERY;
    358   filter_types[kEndedAfterKey] = DownloadQuery::FILTER_ENDED_AFTER;
    359   filter_types[kEndedBeforeKey] = DownloadQuery::FILTER_ENDED_BEFORE;
    360   filter_types[kEndTimeKey] = DownloadQuery::FILTER_END_TIME;
    361   filter_types[kStartedAfterKey] = DownloadQuery::FILTER_STARTED_AFTER;
    362   filter_types[kStartedBeforeKey] = DownloadQuery::FILTER_STARTED_BEFORE;
    363   filter_types[kStartTimeKey] = DownloadQuery::FILTER_START_TIME;
    364   filter_types[kTotalBytesKey] = DownloadQuery::FILTER_TOTAL_BYTES;
    365   filter_types[kTotalBytesGreaterKey] =
    366     DownloadQuery::FILTER_TOTAL_BYTES_GREATER;
    367   filter_types[kTotalBytesLessKey] = DownloadQuery::FILTER_TOTAL_BYTES_LESS;
    368   filter_types[kUrlKey] = DownloadQuery::FILTER_URL;
    369   filter_types[kUrlRegexKey] = DownloadQuery::FILTER_URL_REGEX;
    370 }
    371 
    372 typedef base::hash_map<std::string, DownloadQuery::SortType> SortTypeMap;
    373 
    374 void InitSortTypeMap(SortTypeMap& sorter_types) {
    375   sorter_types[kBytesReceivedKey] = DownloadQuery::SORT_BYTES_RECEIVED;
    376   sorter_types[kDangerKey] = DownloadQuery::SORT_DANGER;
    377   sorter_types[kEndTimeKey] = DownloadQuery::SORT_END_TIME;
    378   sorter_types[kExistsKey] = DownloadQuery::SORT_EXISTS;
    379   sorter_types[kFilenameKey] = DownloadQuery::SORT_FILENAME;
    380   sorter_types[kMimeKey] = DownloadQuery::SORT_MIME;
    381   sorter_types[kPausedKey] = DownloadQuery::SORT_PAUSED;
    382   sorter_types[kStartTimeKey] = DownloadQuery::SORT_START_TIME;
    383   sorter_types[kStateKey] = DownloadQuery::SORT_STATE;
    384   sorter_types[kTotalBytesKey] = DownloadQuery::SORT_TOTAL_BYTES;
    385   sorter_types[kUrlKey] = DownloadQuery::SORT_URL;
    386 }
    387 
    388 bool IsNotTemporaryDownloadFilter(const DownloadItem& download_item) {
    389   return !download_item.IsTemporary();
    390 }
    391 
    392 // Set |manager| to the on-record DownloadManager, and |incognito_manager| to
    393 // the off-record DownloadManager if one exists and is requested via
    394 // |include_incognito|. This should work regardless of whether |profile| is
    395 // original or incognito.
    396 void GetManagers(
    397     Profile* profile,
    398     bool include_incognito,
    399     DownloadManager** manager,
    400     DownloadManager** incognito_manager) {
    401   *manager = BrowserContext::GetDownloadManager(profile->GetOriginalProfile());
    402   if (profile->HasOffTheRecordProfile() &&
    403       (include_incognito ||
    404        profile->IsOffTheRecord())) {
    405     *incognito_manager = BrowserContext::GetDownloadManager(
    406         profile->GetOffTheRecordProfile());
    407   } else {
    408     *incognito_manager = NULL;
    409   }
    410 }
    411 
    412 DownloadItem* GetDownload(Profile* profile, bool include_incognito, int id) {
    413   DownloadManager* manager = NULL;
    414   DownloadManager* incognito_manager = NULL;
    415   GetManagers(profile, include_incognito, &manager, &incognito_manager);
    416   DownloadItem* download_item = manager->GetDownload(id);
    417   if (!download_item && incognito_manager)
    418     download_item = incognito_manager->GetDownload(id);
    419   return download_item;
    420 }
    421 
    422 enum DownloadsFunctionName {
    423   DOWNLOADS_FUNCTION_DOWNLOAD = 0,
    424   DOWNLOADS_FUNCTION_SEARCH = 1,
    425   DOWNLOADS_FUNCTION_PAUSE = 2,
    426   DOWNLOADS_FUNCTION_RESUME = 3,
    427   DOWNLOADS_FUNCTION_CANCEL = 4,
    428   DOWNLOADS_FUNCTION_ERASE = 5,
    429   // 6 unused
    430   DOWNLOADS_FUNCTION_ACCEPT_DANGER = 7,
    431   DOWNLOADS_FUNCTION_SHOW = 8,
    432   DOWNLOADS_FUNCTION_DRAG = 9,
    433   DOWNLOADS_FUNCTION_GET_FILE_ICON = 10,
    434   DOWNLOADS_FUNCTION_OPEN = 11,
    435   DOWNLOADS_FUNCTION_REMOVE_FILE = 12,
    436   DOWNLOADS_FUNCTION_SHOW_DEFAULT_FOLDER = 13,
    437   DOWNLOADS_FUNCTION_SET_SHELF_ENABLED = 14,
    438   // Insert new values here, not at the beginning.
    439   DOWNLOADS_FUNCTION_LAST
    440 };
    441 
    442 void RecordApiFunctions(DownloadsFunctionName function) {
    443   UMA_HISTOGRAM_ENUMERATION("Download.ApiFunctions",
    444                             function,
    445                             DOWNLOADS_FUNCTION_LAST);
    446 }
    447 
    448 void CompileDownloadQueryOrderBy(
    449     const std::vector<std::string>& order_by_strs,
    450     std::string* error,
    451     DownloadQuery* query) {
    452   // TODO(benjhayden): Consider switching from LazyInstance to explicit string
    453   // comparisons.
    454   static base::LazyInstance<SortTypeMap> sorter_types =
    455     LAZY_INSTANCE_INITIALIZER;
    456   if (sorter_types.Get().size() == 0)
    457     InitSortTypeMap(sorter_types.Get());
    458 
    459   for (std::vector<std::string>::const_iterator iter = order_by_strs.begin();
    460        iter != order_by_strs.end(); ++iter) {
    461     std::string term_str = *iter;
    462     if (term_str.empty())
    463       continue;
    464     DownloadQuery::SortDirection direction = DownloadQuery::ASCENDING;
    465     if (term_str[0] == '-') {
    466       direction = DownloadQuery::DESCENDING;
    467       term_str = term_str.substr(1);
    468     }
    469     SortTypeMap::const_iterator sorter_type =
    470         sorter_types.Get().find(term_str);
    471     if (sorter_type == sorter_types.Get().end()) {
    472       *error = errors::kInvalidOrderBy;
    473       return;
    474     }
    475     query->AddSorter(sorter_type->second, direction);
    476   }
    477 }
    478 
    479 void RunDownloadQuery(
    480     const downloads::DownloadQuery& query_in,
    481     DownloadManager* manager,
    482     DownloadManager* incognito_manager,
    483     std::string* error,
    484     DownloadQuery::DownloadVector* results) {
    485   // TODO(benjhayden): Consider switching from LazyInstance to explicit string
    486   // comparisons.
    487   static base::LazyInstance<FilterTypeMap> filter_types =
    488     LAZY_INSTANCE_INITIALIZER;
    489   if (filter_types.Get().size() == 0)
    490     InitFilterTypeMap(filter_types.Get());
    491 
    492   DownloadQuery query_out;
    493 
    494   size_t limit = 1000;
    495   if (query_in.limit.get()) {
    496     if (*query_in.limit.get() < 0) {
    497       *error = errors::kInvalidQueryLimit;
    498       return;
    499     }
    500     limit = *query_in.limit.get();
    501   }
    502   if (limit > 0) {
    503     query_out.Limit(limit);
    504   }
    505 
    506   std::string state_string =
    507       downloads::ToString(query_in.state);
    508   if (!state_string.empty()) {
    509     DownloadItem::DownloadState state = StateEnumFromString(state_string);
    510     if (state == DownloadItem::MAX_DOWNLOAD_STATE) {
    511       *error = errors::kInvalidState;
    512       return;
    513     }
    514     query_out.AddFilter(state);
    515   }
    516   std::string danger_string =
    517       downloads::ToString(query_in.danger);
    518   if (!danger_string.empty()) {
    519     content::DownloadDangerType danger_type = DangerEnumFromString(
    520         danger_string);
    521     if (danger_type == content::DOWNLOAD_DANGER_TYPE_MAX) {
    522       *error = errors::kInvalidDangerType;
    523       return;
    524     }
    525     query_out.AddFilter(danger_type);
    526   }
    527   if (query_in.order_by.get()) {
    528     CompileDownloadQueryOrderBy(*query_in.order_by.get(), error, &query_out);
    529     if (!error->empty())
    530       return;
    531   }
    532 
    533   scoped_ptr<base::DictionaryValue> query_in_value(query_in.ToValue().Pass());
    534   for (base::DictionaryValue::Iterator query_json_field(*query_in_value.get());
    535        !query_json_field.IsAtEnd(); query_json_field.Advance()) {
    536     FilterTypeMap::const_iterator filter_type =
    537         filter_types.Get().find(query_json_field.key());
    538     if (filter_type != filter_types.Get().end()) {
    539       if (!query_out.AddFilter(filter_type->second, query_json_field.value())) {
    540         *error = errors::kInvalidFilter;
    541         return;
    542       }
    543     }
    544   }
    545 
    546   DownloadQuery::DownloadVector all_items;
    547   if (query_in.id.get()) {
    548     DownloadItem* download_item = manager->GetDownload(*query_in.id.get());
    549     if (!download_item && incognito_manager)
    550       download_item = incognito_manager->GetDownload(*query_in.id.get());
    551     if (download_item)
    552       all_items.push_back(download_item);
    553   } else {
    554     manager->GetAllDownloads(&all_items);
    555     if (incognito_manager)
    556       incognito_manager->GetAllDownloads(&all_items);
    557   }
    558   query_out.AddFilter(base::Bind(&IsNotTemporaryDownloadFilter));
    559   query_out.Search(all_items.begin(), all_items.end(), results);
    560 }
    561 
    562 DownloadPathReservationTracker::FilenameConflictAction ConvertConflictAction(
    563     downloads::FilenameConflictAction action) {
    564   switch (action) {
    565     case downloads::FILENAME_CONFLICT_ACTION_NONE:
    566     case downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY:
    567       return DownloadPathReservationTracker::UNIQUIFY;
    568     case downloads::FILENAME_CONFLICT_ACTION_OVERWRITE:
    569       return DownloadPathReservationTracker::OVERWRITE;
    570     case downloads::FILENAME_CONFLICT_ACTION_PROMPT:
    571       return DownloadPathReservationTracker::PROMPT;
    572   }
    573   NOTREACHED();
    574   return DownloadPathReservationTracker::UNIQUIFY;
    575 }
    576 
    577 class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data {
    578  public:
    579   static ExtensionDownloadsEventRouterData* Get(DownloadItem* download_item) {
    580     base::SupportsUserData::Data* data = download_item->GetUserData(kKey);
    581     return (data == NULL) ? NULL :
    582         static_cast<ExtensionDownloadsEventRouterData*>(data);
    583   }
    584 
    585   static void Remove(DownloadItem* download_item) {
    586     download_item->RemoveUserData(kKey);
    587   }
    588 
    589   explicit ExtensionDownloadsEventRouterData(
    590       DownloadItem* download_item,
    591       scoped_ptr<base::DictionaryValue> json_item)
    592       : updated_(0),
    593         changed_fired_(0),
    594         json_(json_item.Pass()),
    595         creator_conflict_action_(
    596             downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY),
    597         determined_conflict_action_(
    598             downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) {
    599     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    600     download_item->SetUserData(kKey, this);
    601   }
    602 
    603   virtual ~ExtensionDownloadsEventRouterData() {
    604     if (updated_ > 0) {
    605       UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged",
    606                                (changed_fired_ * 100 / updated_));
    607     }
    608   }
    609 
    610   const base::DictionaryValue& json() const { return *json_.get(); }
    611   void set_json(scoped_ptr<base::DictionaryValue> json_item) {
    612     json_ = json_item.Pass();
    613   }
    614 
    615   void OnItemUpdated() { ++updated_; }
    616   void OnChangedFired() { ++changed_fired_; }
    617 
    618   void set_filename_change_callbacks(
    619       const base::Closure& no_change,
    620       const ExtensionDownloadsEventRouter::FilenameChangedCallback& change) {
    621     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    622     filename_no_change_ = no_change;
    623     filename_change_ = change;
    624     determined_filename_ = creator_suggested_filename_;
    625     determined_conflict_action_ = creator_conflict_action_;
    626     // determiner_.install_time should default to 0 so that creator suggestions
    627     // should be lower priority than any actual onDeterminingFilename listeners.
    628   }
    629 
    630   void ClearPendingDeterminers() {
    631     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    632     determined_filename_.clear();
    633     determined_conflict_action_ =
    634       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY;
    635     determiner_ = DeterminerInfo();
    636     filename_no_change_ = base::Closure();
    637     filename_change_ = ExtensionDownloadsEventRouter::FilenameChangedCallback();
    638     weak_ptr_factory_.reset();
    639     determiners_.clear();
    640   }
    641 
    642   void DeterminerRemoved(const std::string& extension_id) {
    643     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    644     for (DeterminerInfoVector::iterator iter = determiners_.begin();
    645          iter != determiners_.end();) {
    646       if (iter->extension_id == extension_id) {
    647         iter = determiners_.erase(iter);
    648       } else {
    649         ++iter;
    650       }
    651     }
    652     // If we just removed the last unreported determiner, then we need to call a
    653     // callback.
    654     CheckAllDeterminersCalled();
    655   }
    656 
    657   void AddPendingDeterminer(const std::string& extension_id,
    658                             const base::Time& installed) {
    659     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    660     for (size_t index = 0; index < determiners_.size(); ++index) {
    661       if (determiners_[index].extension_id == extension_id) {
    662         DCHECK(false) << extension_id;
    663         return;
    664       }
    665     }
    666     determiners_.push_back(DeterminerInfo(extension_id, installed));
    667   }
    668 
    669   bool DeterminerAlreadyReported(const std::string& extension_id) {
    670     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    671     for (size_t index = 0; index < determiners_.size(); ++index) {
    672       if (determiners_[index].extension_id == extension_id) {
    673         return determiners_[index].reported;
    674       }
    675     }
    676     return false;
    677   }
    678 
    679   void CreatorSuggestedFilename(
    680       const base::FilePath& filename,
    681       downloads::FilenameConflictAction conflict_action) {
    682     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    683     creator_suggested_filename_ = filename;
    684     creator_conflict_action_ = conflict_action;
    685   }
    686 
    687   base::FilePath creator_suggested_filename() const {
    688     return creator_suggested_filename_;
    689   }
    690 
    691   downloads::FilenameConflictAction
    692   creator_conflict_action() const {
    693     return creator_conflict_action_;
    694   }
    695 
    696   void ResetCreatorSuggestion() {
    697     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    698     creator_suggested_filename_.clear();
    699     creator_conflict_action_ =
    700       downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY;
    701   }
    702 
    703   // Returns false if this |extension_id| was not expected or if this
    704   // |extension_id| has already reported. The caller is responsible for
    705   // validating |filename|.
    706   bool DeterminerCallback(
    707       Profile* profile,
    708       const std::string& extension_id,
    709       const base::FilePath& filename,
    710       downloads::FilenameConflictAction conflict_action) {
    711     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    712     bool found_info = false;
    713     for (size_t index = 0; index < determiners_.size(); ++index) {
    714       if (determiners_[index].extension_id == extension_id) {
    715         found_info = true;
    716         if (determiners_[index].reported)
    717           return false;
    718         determiners_[index].reported = true;
    719         // Do not use filename if another determiner has already overridden the
    720         // filename and they take precedence. Extensions that were installed
    721         // later take precedence over previous extensions.
    722         if (!filename.empty()) {
    723           extensions::ExtensionWarningSet warnings;
    724           std::string winner_extension_id;
    725           ExtensionDownloadsEventRouter::DetermineFilenameInternal(
    726               filename,
    727               conflict_action,
    728               determiners_[index].extension_id,
    729               determiners_[index].install_time,
    730               determiner_.extension_id,
    731               determiner_.install_time,
    732               &winner_extension_id,
    733               &determined_filename_,
    734               &determined_conflict_action_,
    735               &warnings);
    736           if (!warnings.empty())
    737             extensions::ExtensionWarningService::NotifyWarningsOnUI(
    738                 profile, warnings);
    739           if (winner_extension_id == determiners_[index].extension_id)
    740             determiner_ = determiners_[index];
    741         }
    742         break;
    743       }
    744     }
    745     if (!found_info)
    746       return false;
    747     CheckAllDeterminersCalled();
    748     return true;
    749   }
    750 
    751  private:
    752   struct DeterminerInfo {
    753     DeterminerInfo();
    754     DeterminerInfo(const std::string& e_id,
    755                    const base::Time& installed);
    756     ~DeterminerInfo();
    757 
    758     std::string extension_id;
    759     base::Time install_time;
    760     bool reported;
    761   };
    762   typedef std::vector<DeterminerInfo> DeterminerInfoVector;
    763 
    764   static const char kKey[];
    765 
    766   // This is safe to call even while not waiting for determiners to call back;
    767   // in that case, the callbacks will be null so they won't be Run.
    768   void CheckAllDeterminersCalled() {
    769     for (DeterminerInfoVector::iterator iter = determiners_.begin();
    770          iter != determiners_.end(); ++iter) {
    771       if (!iter->reported)
    772         return;
    773     }
    774     if (determined_filename_.empty()) {
    775       if (!filename_no_change_.is_null())
    776         filename_no_change_.Run();
    777     } else {
    778       if (!filename_change_.is_null()) {
    779         filename_change_.Run(determined_filename_, ConvertConflictAction(
    780             determined_conflict_action_));
    781       }
    782     }
    783     // Don't clear determiners_ immediately in case there's a second listener
    784     // for one of the extensions, so that DetermineFilename can return
    785     // kTooManyListeners. After a few seconds, DetermineFilename will return
    786     // kUnexpectedDeterminer instead of kTooManyListeners so that determiners_
    787     // doesn't keep hogging memory.
    788     weak_ptr_factory_.reset(
    789         new base::WeakPtrFactory<ExtensionDownloadsEventRouterData>(this));
    790     base::MessageLoopForUI::current()->PostDelayedTask(
    791         FROM_HERE,
    792         base::Bind(&ExtensionDownloadsEventRouterData::ClearPendingDeterminers,
    793                    weak_ptr_factory_->GetWeakPtr()),
    794         base::TimeDelta::FromSeconds(30));
    795   }
    796 
    797   int updated_;
    798   int changed_fired_;
    799   scoped_ptr<base::DictionaryValue> json_;
    800 
    801   base::Closure filename_no_change_;
    802   ExtensionDownloadsEventRouter::FilenameChangedCallback filename_change_;
    803 
    804   DeterminerInfoVector determiners_;
    805 
    806   base::FilePath creator_suggested_filename_;
    807   downloads::FilenameConflictAction
    808     creator_conflict_action_;
    809   base::FilePath determined_filename_;
    810   downloads::FilenameConflictAction
    811     determined_conflict_action_;
    812   DeterminerInfo determiner_;
    813 
    814   scoped_ptr<base::WeakPtrFactory<ExtensionDownloadsEventRouterData> >
    815     weak_ptr_factory_;
    816 
    817   DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouterData);
    818 };
    819 
    820 ExtensionDownloadsEventRouterData::DeterminerInfo::DeterminerInfo(
    821     const std::string& e_id,
    822     const base::Time& installed)
    823     : extension_id(e_id),
    824       install_time(installed),
    825       reported(false) {
    826 }
    827 
    828 ExtensionDownloadsEventRouterData::DeterminerInfo::DeterminerInfo()
    829     : reported(false) {
    830 }
    831 
    832 ExtensionDownloadsEventRouterData::DeterminerInfo::~DeterminerInfo() {}
    833 
    834 const char ExtensionDownloadsEventRouterData::kKey[] =
    835   "DownloadItem ExtensionDownloadsEventRouterData";
    836 
    837 class ManagerDestructionObserver : public DownloadManager::Observer {
    838  public:
    839   static void CheckForHistoryFilesRemoval(DownloadManager* manager) {
    840     if (!manager)
    841       return;
    842     if (!manager_file_existence_last_checked_)
    843       manager_file_existence_last_checked_ =
    844         new std::map<DownloadManager*, ManagerDestructionObserver*>();
    845     if (!(*manager_file_existence_last_checked_)[manager])
    846       (*manager_file_existence_last_checked_)[manager] =
    847         new ManagerDestructionObserver(manager);
    848     (*manager_file_existence_last_checked_)[manager]->
    849       CheckForHistoryFilesRemovalInternal();
    850   }
    851 
    852  private:
    853   static const int kFileExistenceRateLimitSeconds = 10;
    854 
    855   explicit ManagerDestructionObserver(DownloadManager* manager)
    856       : manager_(manager) {
    857     manager_->AddObserver(this);
    858   }
    859 
    860   virtual ~ManagerDestructionObserver() {
    861     manager_->RemoveObserver(this);
    862   }
    863 
    864   virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE {
    865     manager_file_existence_last_checked_->erase(manager);
    866     if (manager_file_existence_last_checked_->size() == 0) {
    867       delete manager_file_existence_last_checked_;
    868       manager_file_existence_last_checked_ = NULL;
    869     }
    870   }
    871 
    872   void CheckForHistoryFilesRemovalInternal() {
    873     base::Time now(base::Time::Now());
    874     int delta = now.ToTimeT() - last_checked_.ToTimeT();
    875     if (delta > kFileExistenceRateLimitSeconds) {
    876       last_checked_ = now;
    877       manager_->CheckForHistoryFilesRemoval();
    878     }
    879   }
    880 
    881   static std::map<DownloadManager*, ManagerDestructionObserver*>*
    882     manager_file_existence_last_checked_;
    883 
    884   DownloadManager* manager_;
    885   base::Time last_checked_;
    886 
    887   DISALLOW_COPY_AND_ASSIGN(ManagerDestructionObserver);
    888 };
    889 
    890 std::map<DownloadManager*, ManagerDestructionObserver*>*
    891   ManagerDestructionObserver::manager_file_existence_last_checked_ = NULL;
    892 
    893 void OnDeterminingFilenameWillDispatchCallback(
    894     bool* any_determiners,
    895     ExtensionDownloadsEventRouterData* data,
    896     content::BrowserContext* context,
    897     const extensions::Extension* extension,
    898     base::ListValue* event_args) {
    899   *any_determiners = true;
    900   base::Time installed = extensions::ExtensionSystem::GetForBrowserContext(
    901       context)->extension_service()->extension_prefs()->
    902     GetInstallTime(extension->id());
    903   data->AddPendingDeterminer(extension->id(), installed);
    904 }
    905 
    906 bool Fault(bool error,
    907            const char* message_in,
    908            std::string* message_out) {
    909   if (!error)
    910     return false;
    911   *message_out = message_in;
    912   return true;
    913 }
    914 
    915 bool InvalidId(DownloadItem* valid_item, std::string* message_out) {
    916   return Fault(!valid_item, errors::kInvalidId, message_out);
    917 }
    918 
    919 bool IsDownloadDeltaField(const std::string& field) {
    920   return ((field == kUrlKey) ||
    921           (field == kFilenameKey) ||
    922           (field == kDangerKey) ||
    923           (field == kMimeKey) ||
    924           (field == kStartTimeKey) ||
    925           (field == kEndTimeKey) ||
    926           (field == kStateKey) ||
    927           (field == kCanResumeKey) ||
    928           (field == kPausedKey) ||
    929           (field == kErrorKey) ||
    930           (field == kTotalBytesKey) ||
    931           (field == kFileSizeKey) ||
    932           (field == kExistsKey));
    933 }
    934 
    935 }  // namespace
    936 
    937 const char DownloadedByExtension::kKey[] =
    938   "DownloadItem DownloadedByExtension";
    939 
    940 DownloadedByExtension* DownloadedByExtension::Get(
    941     content::DownloadItem* item) {
    942   base::SupportsUserData::Data* data = item->GetUserData(kKey);
    943   return (data == NULL) ? NULL :
    944       static_cast<DownloadedByExtension*>(data);
    945 }
    946 
    947 DownloadedByExtension::DownloadedByExtension(
    948     content::DownloadItem* item,
    949     const std::string& id,
    950     const std::string& name)
    951   : id_(id),
    952     name_(name) {
    953   item->SetUserData(kKey, this);
    954 }
    955 
    956 DownloadsDownloadFunction::DownloadsDownloadFunction() {}
    957 
    958 DownloadsDownloadFunction::~DownloadsDownloadFunction() {}
    959 
    960 bool DownloadsDownloadFunction::RunImpl() {
    961   scoped_ptr<downloads::Download::Params> params(
    962       downloads::Download::Params::Create(*args_));
    963   EXTENSION_FUNCTION_VALIDATE(params.get());
    964   const downloads::DownloadOptions& options = params->options;
    965   GURL download_url(options.url);
    966   if (Fault(!download_url.is_valid(), errors::kInvalidURL, &error_))
    967     return false;
    968 
    969   Profile* current_profile = GetProfile();
    970   if (include_incognito() && GetProfile()->HasOffTheRecordProfile())
    971     current_profile = GetProfile()->GetOffTheRecordProfile();
    972 
    973   scoped_ptr<content::DownloadUrlParameters> download_params(
    974       new content::DownloadUrlParameters(
    975           download_url,
    976           render_view_host()->GetProcess()->GetID(),
    977           render_view_host()->GetRoutingID(),
    978           current_profile->GetResourceContext()));
    979 
    980   base::FilePath creator_suggested_filename;
    981   if (options.filename.get()) {
    982 #if defined(OS_WIN)
    983     // Can't get filename16 from options.ToValue() because that converts it from
    984     // std::string.
    985     base::DictionaryValue* options_value = NULL;
    986     EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_value));
    987     base::string16 filename16;
    988     EXTENSION_FUNCTION_VALIDATE(options_value->GetString(
    989         kFilenameKey, &filename16));
    990     creator_suggested_filename = base::FilePath(filename16);
    991 #elif defined(OS_POSIX)
    992     creator_suggested_filename = base::FilePath(*options.filename.get());
    993 #endif
    994     if (!net::IsSafePortableRelativePath(creator_suggested_filename)) {
    995       error_ = errors::kInvalidFilename;
    996       return false;
    997     }
    998   }
    999 
   1000   if (options.save_as.get())
   1001     download_params->set_prompt(*options.save_as.get());
   1002 
   1003   if (options.headers.get()) {
   1004     typedef downloads::HeaderNameValuePair HeaderNameValuePair;
   1005     for (std::vector<linked_ptr<HeaderNameValuePair> >::const_iterator iter =
   1006          options.headers->begin();
   1007          iter != options.headers->end();
   1008          ++iter) {
   1009       const HeaderNameValuePair& name_value = **iter;
   1010       if (!net::HttpUtil::IsSafeHeader(name_value.name)) {
   1011         error_ = errors::kInvalidHeader;
   1012         return false;
   1013       }
   1014       download_params->add_request_header(name_value.name, name_value.value);
   1015     }
   1016   }
   1017 
   1018   std::string method_string =
   1019       downloads::ToString(options.method);
   1020   if (!method_string.empty())
   1021     download_params->set_method(method_string);
   1022   if (options.body.get())
   1023     download_params->set_post_body(*options.body.get());
   1024   download_params->set_callback(base::Bind(
   1025       &DownloadsDownloadFunction::OnStarted, this,
   1026       creator_suggested_filename, options.conflict_action));
   1027   // Prevent login prompts for 401/407 responses.
   1028   download_params->set_load_flags(net::LOAD_DO_NOT_PROMPT_FOR_LOGIN);
   1029 
   1030   DownloadManager* manager = BrowserContext::GetDownloadManager(
   1031       current_profile);
   1032   manager->DownloadUrl(download_params.Pass());
   1033   RecordDownloadSource(DOWNLOAD_INITIATED_BY_EXTENSION);
   1034   RecordApiFunctions(DOWNLOADS_FUNCTION_DOWNLOAD);
   1035   return true;
   1036 }
   1037 
   1038 void DownloadsDownloadFunction::OnStarted(
   1039     const base::FilePath& creator_suggested_filename,
   1040     downloads::FilenameConflictAction creator_conflict_action,
   1041     DownloadItem* item,
   1042     net::Error error) {
   1043   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1044   VLOG(1) << __FUNCTION__ << " " << item << " " << error;
   1045   if (item) {
   1046     DCHECK_EQ(net::OK, error);
   1047     SetResult(new base::FundamentalValue(static_cast<int>(item->GetId())));
   1048     if (!creator_suggested_filename.empty()) {
   1049       ExtensionDownloadsEventRouterData* data =
   1050           ExtensionDownloadsEventRouterData::Get(item);
   1051       if (!data) {
   1052         data = new ExtensionDownloadsEventRouterData(
   1053             item,
   1054             scoped_ptr<base::DictionaryValue>(new base::DictionaryValue()));
   1055       }
   1056       data->CreatorSuggestedFilename(
   1057           creator_suggested_filename, creator_conflict_action);
   1058     }
   1059     new DownloadedByExtension(
   1060         item, GetExtension()->id(), GetExtension()->name());
   1061     item->UpdateObservers();
   1062   } else {
   1063     DCHECK_NE(net::OK, error);
   1064     error_ = net::ErrorToString(error);
   1065   }
   1066   SendResponse(error_.empty());
   1067 }
   1068 
   1069 DownloadsSearchFunction::DownloadsSearchFunction() {}
   1070 
   1071 DownloadsSearchFunction::~DownloadsSearchFunction() {}
   1072 
   1073 bool DownloadsSearchFunction::RunImpl() {
   1074   scoped_ptr<downloads::Search::Params> params(
   1075       downloads::Search::Params::Create(*args_));
   1076   EXTENSION_FUNCTION_VALIDATE(params.get());
   1077   DownloadManager* manager = NULL;
   1078   DownloadManager* incognito_manager = NULL;
   1079   GetManagers(GetProfile(), include_incognito(), &manager, &incognito_manager);
   1080   ManagerDestructionObserver::CheckForHistoryFilesRemoval(manager);
   1081   ManagerDestructionObserver::CheckForHistoryFilesRemoval(incognito_manager);
   1082   DownloadQuery::DownloadVector results;
   1083   RunDownloadQuery(params->query,
   1084                    manager,
   1085                    incognito_manager,
   1086                    &error_,
   1087                    &results);
   1088   if (!error_.empty())
   1089     return false;
   1090 
   1091   base::ListValue* json_results = new base::ListValue();
   1092   for (DownloadManager::DownloadVector::const_iterator it = results.begin();
   1093        it != results.end(); ++it) {
   1094     DownloadItem* download_item = *it;
   1095     uint32 download_id = download_item->GetId();
   1096     bool off_record = ((incognito_manager != NULL) &&
   1097                        (incognito_manager->GetDownload(download_id) != NULL));
   1098     scoped_ptr<base::DictionaryValue> json_item(
   1099         DownloadItemToJSON(*it,
   1100                            off_record ? GetProfile()->GetOffTheRecordProfile()
   1101                                       : GetProfile()->GetOriginalProfile()));
   1102     json_results->Append(json_item.release());
   1103   }
   1104   SetResult(json_results);
   1105   RecordApiFunctions(DOWNLOADS_FUNCTION_SEARCH);
   1106   return true;
   1107 }
   1108 
   1109 DownloadsPauseFunction::DownloadsPauseFunction() {}
   1110 
   1111 DownloadsPauseFunction::~DownloadsPauseFunction() {}
   1112 
   1113 bool DownloadsPauseFunction::RunImpl() {
   1114   scoped_ptr<downloads::Pause::Params> params(
   1115       downloads::Pause::Params::Create(*args_));
   1116   EXTENSION_FUNCTION_VALIDATE(params.get());
   1117   DownloadItem* download_item =
   1118       GetDownload(GetProfile(), include_incognito(), params->download_id);
   1119   if (InvalidId(download_item, &error_) ||
   1120       Fault(download_item->GetState() != DownloadItem::IN_PROGRESS,
   1121             errors::kNotInProgress, &error_))
   1122     return false;
   1123   // If the item is already paused, this is a no-op and the operation will
   1124   // silently succeed.
   1125   download_item->Pause();
   1126   RecordApiFunctions(DOWNLOADS_FUNCTION_PAUSE);
   1127   return true;
   1128 }
   1129 
   1130 DownloadsResumeFunction::DownloadsResumeFunction() {}
   1131 
   1132 DownloadsResumeFunction::~DownloadsResumeFunction() {}
   1133 
   1134 bool DownloadsResumeFunction::RunImpl() {
   1135   scoped_ptr<downloads::Resume::Params> params(
   1136       downloads::Resume::Params::Create(*args_));
   1137   EXTENSION_FUNCTION_VALIDATE(params.get());
   1138   DownloadItem* download_item =
   1139       GetDownload(GetProfile(), include_incognito(), params->download_id);
   1140   if (InvalidId(download_item, &error_) ||
   1141       Fault(download_item->IsPaused() && !download_item->CanResume(),
   1142             errors::kNotResumable, &error_))
   1143     return false;
   1144   // Note that if the item isn't paused, this will be a no-op, and the extension
   1145   // call will seem successful.
   1146   download_item->Resume();
   1147   RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME);
   1148   return true;
   1149 }
   1150 
   1151 DownloadsCancelFunction::DownloadsCancelFunction() {}
   1152 
   1153 DownloadsCancelFunction::~DownloadsCancelFunction() {}
   1154 
   1155 bool DownloadsCancelFunction::RunImpl() {
   1156   scoped_ptr<downloads::Resume::Params> params(
   1157       downloads::Resume::Params::Create(*args_));
   1158   EXTENSION_FUNCTION_VALIDATE(params.get());
   1159   DownloadItem* download_item =
   1160       GetDownload(GetProfile(), include_incognito(), params->download_id);
   1161   if (download_item &&
   1162       (download_item->GetState() == DownloadItem::IN_PROGRESS))
   1163     download_item->Cancel(true);
   1164   // |download_item| can be NULL if the download ID was invalid or if the
   1165   // download is not currently active.  Either way, it's not a failure.
   1166   RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL);
   1167   return true;
   1168 }
   1169 
   1170 DownloadsEraseFunction::DownloadsEraseFunction() {}
   1171 
   1172 DownloadsEraseFunction::~DownloadsEraseFunction() {}
   1173 
   1174 bool DownloadsEraseFunction::RunImpl() {
   1175   scoped_ptr<downloads::Erase::Params> params(
   1176       downloads::Erase::Params::Create(*args_));
   1177   EXTENSION_FUNCTION_VALIDATE(params.get());
   1178   DownloadManager* manager = NULL;
   1179   DownloadManager* incognito_manager = NULL;
   1180   GetManagers(GetProfile(), include_incognito(), &manager, &incognito_manager);
   1181   DownloadQuery::DownloadVector results;
   1182   RunDownloadQuery(params->query,
   1183                    manager,
   1184                    incognito_manager,
   1185                    &error_,
   1186                    &results);
   1187   if (!error_.empty())
   1188     return false;
   1189   base::ListValue* json_results = new base::ListValue();
   1190   for (DownloadManager::DownloadVector::const_iterator it = results.begin();
   1191        it != results.end(); ++it) {
   1192     json_results->Append(
   1193         new base::FundamentalValue(static_cast<int>((*it)->GetId())));
   1194     (*it)->Remove();
   1195   }
   1196   SetResult(json_results);
   1197   RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE);
   1198   return true;
   1199 }
   1200 
   1201 DownloadsRemoveFileFunction::DownloadsRemoveFileFunction()
   1202     : item_(NULL) {
   1203 }
   1204 
   1205 DownloadsRemoveFileFunction::~DownloadsRemoveFileFunction() {
   1206   if (item_) {
   1207     item_->RemoveObserver(this);
   1208     item_ = NULL;
   1209   }
   1210 }
   1211 
   1212 bool DownloadsRemoveFileFunction::RunImpl() {
   1213   scoped_ptr<downloads::RemoveFile::Params> params(
   1214       downloads::RemoveFile::Params::Create(*args_));
   1215   EXTENSION_FUNCTION_VALIDATE(params.get());
   1216   DownloadItem* download_item =
   1217       GetDownload(GetProfile(), include_incognito(), params->download_id);
   1218   if (InvalidId(download_item, &error_) ||
   1219       Fault((download_item->GetState() != DownloadItem::COMPLETE),
   1220             errors::kNotComplete, &error_) ||
   1221       Fault(download_item->GetFileExternallyRemoved(),
   1222             errors::kFileAlreadyDeleted, &error_))
   1223     return false;
   1224   item_ = download_item;
   1225   item_->AddObserver(this);
   1226   RecordApiFunctions(DOWNLOADS_FUNCTION_REMOVE_FILE);
   1227   download_item->DeleteFile();
   1228   return true;
   1229 }
   1230 
   1231 void DownloadsRemoveFileFunction::OnDownloadUpdated(DownloadItem* download) {
   1232   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1233   DCHECK_EQ(item_, download);
   1234   if (!item_->GetFileExternallyRemoved())
   1235     return;
   1236   item_->RemoveObserver(this);
   1237   item_ = NULL;
   1238   SendResponse(true);
   1239 }
   1240 
   1241 void DownloadsRemoveFileFunction::OnDownloadDestroyed(DownloadItem* download) {
   1242   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1243   DCHECK_EQ(item_, download);
   1244   item_->RemoveObserver(this);
   1245   item_ = NULL;
   1246   SendResponse(true);
   1247 }
   1248 
   1249 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {}
   1250 
   1251 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {}
   1252 
   1253 DownloadsAcceptDangerFunction::OnPromptCreatedCallback*
   1254     DownloadsAcceptDangerFunction::on_prompt_created_ = NULL;
   1255 
   1256 bool DownloadsAcceptDangerFunction::RunImpl() {
   1257   scoped_ptr<downloads::AcceptDanger::Params> params(
   1258       downloads::AcceptDanger::Params::Create(*args_));
   1259   EXTENSION_FUNCTION_VALIDATE(params.get());
   1260   PromptOrWait(params->download_id, 10);
   1261   return true;
   1262 }
   1263 
   1264 void DownloadsAcceptDangerFunction::PromptOrWait(int download_id, int retries) {
   1265   DownloadItem* download_item =
   1266       GetDownload(GetProfile(), include_incognito(), download_id);
   1267   content::WebContents* web_contents =
   1268       dispatcher()->delegate()->GetVisibleWebContents();
   1269   if (InvalidId(download_item, &error_) ||
   1270       Fault(download_item->GetState() != DownloadItem::IN_PROGRESS,
   1271             errors::kNotInProgress, &error_) ||
   1272       Fault(!download_item->IsDangerous(), errors::kNotDangerous, &error_) ||
   1273       Fault(!web_contents, errors::kInvisibleContext, &error_)) {
   1274     SendResponse(error_.empty());
   1275     return;
   1276   }
   1277   bool visible = platform_util::IsVisible(
   1278       web_contents->GetView()->GetNativeView());
   1279   if (!visible) {
   1280     if (retries > 0) {
   1281       base::MessageLoopForUI::current()->PostDelayedTask(
   1282           FROM_HERE,
   1283           base::Bind(&DownloadsAcceptDangerFunction::PromptOrWait,
   1284                      this, download_id, retries - 1),
   1285           base::TimeDelta::FromMilliseconds(100));
   1286       return;
   1287     }
   1288     error_ = errors::kInvisibleContext;
   1289     SendResponse(error_.empty());
   1290     return;
   1291   }
   1292   RecordApiFunctions(DOWNLOADS_FUNCTION_ACCEPT_DANGER);
   1293   // DownloadDangerPrompt displays a modal dialog using native widgets that the
   1294   // user must either accept or cancel. It cannot be scripted.
   1295   DownloadDangerPrompt* prompt = DownloadDangerPrompt::Create(
   1296       download_item,
   1297       web_contents,
   1298       true,
   1299       base::Bind(&DownloadsAcceptDangerFunction::DangerPromptCallback,
   1300                  this, download_id));
   1301   // DownloadDangerPrompt deletes itself
   1302   if (on_prompt_created_ && !on_prompt_created_->is_null())
   1303     on_prompt_created_->Run(prompt);
   1304   SendResponse(error_.empty());
   1305 }
   1306 
   1307 void DownloadsAcceptDangerFunction::DangerPromptCallback(
   1308     int download_id, DownloadDangerPrompt::Action action) {
   1309   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1310   DownloadItem* download_item =
   1311       GetDownload(GetProfile(), include_incognito(), download_id);
   1312   if (InvalidId(download_item, &error_) ||
   1313       Fault(download_item->GetState() != DownloadItem::IN_PROGRESS,
   1314             errors::kNotInProgress, &error_))
   1315     return;
   1316   switch (action) {
   1317     case DownloadDangerPrompt::ACCEPT:
   1318       download_item->ValidateDangerousDownload();
   1319       break;
   1320     case DownloadDangerPrompt::CANCEL:
   1321       download_item->Remove();
   1322       break;
   1323     case DownloadDangerPrompt::DISMISS:
   1324       break;
   1325   }
   1326   SendResponse(error_.empty());
   1327 }
   1328 
   1329 DownloadsShowFunction::DownloadsShowFunction() {}
   1330 
   1331 DownloadsShowFunction::~DownloadsShowFunction() {}
   1332 
   1333 bool DownloadsShowFunction::RunImpl() {
   1334   scoped_ptr<downloads::Show::Params> params(
   1335       downloads::Show::Params::Create(*args_));
   1336   EXTENSION_FUNCTION_VALIDATE(params.get());
   1337   DownloadItem* download_item =
   1338       GetDownload(GetProfile(), include_incognito(), params->download_id);
   1339   if (InvalidId(download_item, &error_))
   1340     return false;
   1341   download_item->ShowDownloadInShell();
   1342   RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW);
   1343   return true;
   1344 }
   1345 
   1346 DownloadsShowDefaultFolderFunction::DownloadsShowDefaultFolderFunction() {}
   1347 
   1348 DownloadsShowDefaultFolderFunction::~DownloadsShowDefaultFolderFunction() {}
   1349 
   1350 bool DownloadsShowDefaultFolderFunction::RunImpl() {
   1351   DownloadManager* manager = NULL;
   1352   DownloadManager* incognito_manager = NULL;
   1353   GetManagers(GetProfile(), include_incognito(), &manager, &incognito_manager);
   1354   platform_util::OpenItem(
   1355       GetProfile(),
   1356       DownloadPrefs::FromDownloadManager(manager)->DownloadPath());
   1357   RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW_DEFAULT_FOLDER);
   1358   return true;
   1359 }
   1360 
   1361 DownloadsOpenFunction::DownloadsOpenFunction() {}
   1362 
   1363 DownloadsOpenFunction::~DownloadsOpenFunction() {}
   1364 
   1365 bool DownloadsOpenFunction::RunImpl() {
   1366   scoped_ptr<downloads::Open::Params> params(
   1367       downloads::Open::Params::Create(*args_));
   1368   EXTENSION_FUNCTION_VALIDATE(params.get());
   1369   DownloadItem* download_item =
   1370       GetDownload(GetProfile(), include_incognito(), params->download_id);
   1371   if (InvalidId(download_item, &error_) ||
   1372       Fault(download_item->GetState() != DownloadItem::COMPLETE,
   1373             errors::kNotComplete, &error_) ||
   1374       Fault(!GetExtension()->HasAPIPermission(
   1375                 extensions::APIPermission::kDownloadsOpen),
   1376             errors::kOpenPermission, &error_))
   1377     return false;
   1378   download_item->OpenDownload();
   1379   RecordApiFunctions(DOWNLOADS_FUNCTION_OPEN);
   1380   return true;
   1381 }
   1382 
   1383 DownloadsDragFunction::DownloadsDragFunction() {}
   1384 
   1385 DownloadsDragFunction::~DownloadsDragFunction() {}
   1386 
   1387 bool DownloadsDragFunction::RunImpl() {
   1388   scoped_ptr<downloads::Drag::Params> params(
   1389       downloads::Drag::Params::Create(*args_));
   1390   EXTENSION_FUNCTION_VALIDATE(params.get());
   1391   DownloadItem* download_item =
   1392       GetDownload(GetProfile(), include_incognito(), params->download_id);
   1393   content::WebContents* web_contents =
   1394       dispatcher()->delegate()->GetVisibleWebContents();
   1395   if (InvalidId(download_item, &error_) ||
   1396       Fault(!web_contents, errors::kInvisibleContext, &error_))
   1397     return false;
   1398   RecordApiFunctions(DOWNLOADS_FUNCTION_DRAG);
   1399   gfx::Image* icon = g_browser_process->icon_manager()->LookupIconFromFilepath(
   1400       download_item->GetTargetFilePath(), IconLoader::NORMAL);
   1401   gfx::NativeView view = web_contents->GetView()->GetNativeView();
   1402   {
   1403     // Enable nested tasks during DnD, while |DragDownload()| blocks.
   1404     base::MessageLoop::ScopedNestableTaskAllower allow(
   1405         base::MessageLoop::current());
   1406     DragDownloadItem(download_item, icon, view);
   1407   }
   1408   return true;
   1409 }
   1410 
   1411 DownloadsSetShelfEnabledFunction::DownloadsSetShelfEnabledFunction() {}
   1412 
   1413 DownloadsSetShelfEnabledFunction::~DownloadsSetShelfEnabledFunction() {}
   1414 
   1415 bool DownloadsSetShelfEnabledFunction::RunImpl() {
   1416   scoped_ptr<downloads::SetShelfEnabled::Params> params(
   1417       downloads::SetShelfEnabled::Params::Create(*args_));
   1418   EXTENSION_FUNCTION_VALIDATE(params.get());
   1419   if (!GetExtension()->HasAPIPermission(
   1420         extensions::APIPermission::kDownloadsShelf)) {
   1421     error_ = download_extension_errors::kShelfPermission;
   1422     return false;
   1423   }
   1424 
   1425   RecordApiFunctions(DOWNLOADS_FUNCTION_SET_SHELF_ENABLED);
   1426   DownloadManager* manager = NULL;
   1427   DownloadManager* incognito_manager = NULL;
   1428   GetManagers(GetProfile(), include_incognito(), &manager, &incognito_manager);
   1429   DownloadService* service = NULL;
   1430   DownloadService* incognito_service = NULL;
   1431   if (manager) {
   1432     service = DownloadServiceFactory::GetForBrowserContext(
   1433         manager->GetBrowserContext());
   1434     service->GetExtensionEventRouter()->SetShelfEnabled(
   1435         GetExtension(), params->enabled);
   1436   }
   1437   if (incognito_manager) {
   1438     incognito_service = DownloadServiceFactory::GetForBrowserContext(
   1439         incognito_manager->GetBrowserContext());
   1440     incognito_service->GetExtensionEventRouter()->SetShelfEnabled(
   1441         GetExtension(), params->enabled);
   1442   }
   1443 
   1444   BrowserList* browsers = BrowserList::GetInstance(chrome::GetActiveDesktop());
   1445   if (browsers) {
   1446     for (BrowserList::const_iterator iter = browsers->begin();
   1447         iter != browsers->end(); ++iter) {
   1448       const Browser* browser = *iter;
   1449       DownloadService* current_service =
   1450         DownloadServiceFactory::GetForBrowserContext(browser->profile());
   1451       if (((current_service == service) ||
   1452            (current_service == incognito_service)) &&
   1453           browser->window()->IsDownloadShelfVisible() &&
   1454           !current_service->IsShelfEnabled())
   1455         browser->window()->GetDownloadShelf()->Close(DownloadShelf::AUTOMATIC);
   1456     }
   1457   }
   1458 
   1459   if (params->enabled &&
   1460       ((manager && !service->IsShelfEnabled()) ||
   1461        (incognito_manager && !incognito_service->IsShelfEnabled()))) {
   1462     error_ = download_extension_errors::kShelfDisabled;
   1463     return false;
   1464   }
   1465 
   1466   return true;
   1467 }
   1468 
   1469 DownloadsGetFileIconFunction::DownloadsGetFileIconFunction()
   1470     : icon_extractor_(new DownloadFileIconExtractorImpl()) {
   1471 }
   1472 
   1473 DownloadsGetFileIconFunction::~DownloadsGetFileIconFunction() {}
   1474 
   1475 void DownloadsGetFileIconFunction::SetIconExtractorForTesting(
   1476     DownloadFileIconExtractor* extractor) {
   1477   DCHECK(extractor);
   1478   icon_extractor_.reset(extractor);
   1479 }
   1480 
   1481 bool DownloadsGetFileIconFunction::RunImpl() {
   1482   scoped_ptr<downloads::GetFileIcon::Params> params(
   1483       downloads::GetFileIcon::Params::Create(*args_));
   1484   EXTENSION_FUNCTION_VALIDATE(params.get());
   1485   const downloads::GetFileIconOptions* options =
   1486       params->options.get();
   1487   int icon_size = kDefaultIconSize;
   1488   if (options && options->size.get())
   1489     icon_size = *options->size.get();
   1490   DownloadItem* download_item =
   1491       GetDownload(GetProfile(), include_incognito(), params->download_id);
   1492   if (InvalidId(download_item, &error_) ||
   1493       Fault(download_item->GetTargetFilePath().empty(),
   1494             errors::kEmptyFile, &error_))
   1495     return false;
   1496   // In-progress downloads return the intermediate filename for GetFullPath()
   1497   // which doesn't have the final extension. Therefore a good file icon can't be
   1498   // found, so use GetTargetFilePath() instead.
   1499   DCHECK(icon_extractor_.get());
   1500   DCHECK(icon_size == 16 || icon_size == 32);
   1501   EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath(
   1502       download_item->GetTargetFilePath(),
   1503       IconLoaderSizeFromPixelSize(icon_size),
   1504       base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this)));
   1505   return true;
   1506 }
   1507 
   1508 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) {
   1509   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1510   if (Fault(url.empty(), errors::kIconNotFound, &error_)) {
   1511     SendResponse(false);
   1512     return;
   1513   }
   1514   RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON);
   1515   SetResult(new base::StringValue(url));
   1516   SendResponse(true);
   1517 }
   1518 
   1519 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(
   1520     Profile* profile,
   1521     DownloadManager* manager)
   1522     : profile_(profile),
   1523       notifier_(manager, this) {
   1524   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1525   DCHECK(profile_);
   1526   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
   1527                  content::Source<Profile>(profile_));
   1528   extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
   1529       event_router();
   1530   if (router)
   1531     router->RegisterObserver(this,
   1532                              downloads::OnDeterminingFilename::kEventName);
   1533 }
   1534 
   1535 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() {
   1536   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1537   extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
   1538       event_router();
   1539   if (router)
   1540     router->UnregisterObserver(this);
   1541 }
   1542 
   1543 void ExtensionDownloadsEventRouter::SetShelfEnabled(
   1544     const extensions::Extension* extension, bool enabled) {
   1545   std::set<const extensions::Extension*>::iterator iter =
   1546     shelf_disabling_extensions_.find(extension);
   1547   if (iter == shelf_disabling_extensions_.end()) {
   1548     if (!enabled)
   1549       shelf_disabling_extensions_.insert(extension);
   1550   } else if (enabled) {
   1551     shelf_disabling_extensions_.erase(extension);
   1552   }
   1553 }
   1554 
   1555 bool ExtensionDownloadsEventRouter::IsShelfEnabled() const {
   1556   return shelf_disabling_extensions_.empty();
   1557 }
   1558 
   1559 // The method by which extensions hook into the filename determination process
   1560 // is based on the method by which the omnibox API allows extensions to hook
   1561 // into the omnibox autocompletion process. Extensions that wish to play a part
   1562 // in the filename determination process call
   1563 // chrome.downloads.onDeterminingFilename.addListener, which adds an
   1564 // EventListener object to ExtensionEventRouter::listeners().
   1565 //
   1566 // When a download's filename is being determined,
   1567 // ChromeDownloadManagerDelegate::CheckVisitedReferrerBeforeDone (CVRBD) passes
   1568 // 2 callbacks to ExtensionDownloadsEventRouter::OnDeterminingFilename (ODF),
   1569 // which stores the callbacks in the item's ExtensionDownloadsEventRouterData
   1570 // (EDERD) along with all of the extension IDs that are listening for
   1571 // onDeterminingFilename events.  ODF dispatches
   1572 // chrome.downloads.onDeterminingFilename.
   1573 //
   1574 // When the extension's event handler calls |suggestCallback|,
   1575 // downloads_custom_bindings.js calls
   1576 // DownloadsInternalDetermineFilenameFunction::RunImpl, which calls
   1577 // EDER::DetermineFilename, which notifies the item's EDERD.
   1578 //
   1579 // When the last extension's event handler returns, EDERD calls one of the two
   1580 // callbacks that CVRBD passed to ODF, allowing CDMD to complete the filename
   1581 // determination process. If multiple extensions wish to override the filename,
   1582 // then the extension that was last installed wins.
   1583 
   1584 void ExtensionDownloadsEventRouter::OnDeterminingFilename(
   1585     DownloadItem* item,
   1586     const base::FilePath& suggested_path,
   1587     const base::Closure& no_change,
   1588     const FilenameChangedCallback& change) {
   1589   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1590   ExtensionDownloadsEventRouterData* data =
   1591       ExtensionDownloadsEventRouterData::Get(item);
   1592   if (!data) {
   1593     no_change.Run();
   1594     return;
   1595   }
   1596   data->ClearPendingDeterminers();
   1597   data->set_filename_change_callbacks(no_change, change);
   1598   bool any_determiners = false;
   1599   base::DictionaryValue* json = DownloadItemToJSON(
   1600       item, profile_).release();
   1601   json->SetString(kFilenameKey, suggested_path.LossyDisplayName());
   1602   DispatchEvent(downloads::OnDeterminingFilename::kEventName,
   1603                 false,
   1604                 base::Bind(&OnDeterminingFilenameWillDispatchCallback,
   1605                            &any_determiners,
   1606                            data),
   1607                 json);
   1608   if (!any_determiners) {
   1609     data->ClearPendingDeterminers();
   1610     if (!data->creator_suggested_filename().empty()) {
   1611       change.Run(data->creator_suggested_filename(),
   1612                  ConvertConflictAction(data->creator_conflict_action()));
   1613       // If all listeners are removed, don't keep |data| around.
   1614       data->ResetCreatorSuggestion();
   1615     } else {
   1616       no_change.Run();
   1617     }
   1618   }
   1619 }
   1620 
   1621 void ExtensionDownloadsEventRouter::DetermineFilenameInternal(
   1622     const base::FilePath& filename,
   1623     downloads::FilenameConflictAction conflict_action,
   1624     const std::string& suggesting_extension_id,
   1625     const base::Time& suggesting_install_time,
   1626     const std::string& incumbent_extension_id,
   1627     const base::Time& incumbent_install_time,
   1628     std::string* winner_extension_id,
   1629     base::FilePath* determined_filename,
   1630     downloads::FilenameConflictAction*
   1631       determined_conflict_action,
   1632     extensions::ExtensionWarningSet* warnings) {
   1633   DCHECK(!filename.empty());
   1634   DCHECK(!suggesting_extension_id.empty());
   1635 
   1636   if (incumbent_extension_id.empty()) {
   1637     *winner_extension_id = suggesting_extension_id;
   1638     *determined_filename = filename;
   1639     *determined_conflict_action = conflict_action;
   1640     return;
   1641   }
   1642 
   1643   if (suggesting_install_time < incumbent_install_time) {
   1644     *winner_extension_id = incumbent_extension_id;
   1645     warnings->insert(
   1646         extensions::ExtensionWarning::CreateDownloadFilenameConflictWarning(
   1647             suggesting_extension_id,
   1648             incumbent_extension_id,
   1649             filename,
   1650             *determined_filename));
   1651     return;
   1652   }
   1653 
   1654   *winner_extension_id = suggesting_extension_id;
   1655   warnings->insert(
   1656       extensions::ExtensionWarning::CreateDownloadFilenameConflictWarning(
   1657           incumbent_extension_id,
   1658           suggesting_extension_id,
   1659           *determined_filename,
   1660           filename));
   1661   *determined_filename = filename;
   1662   *determined_conflict_action = conflict_action;
   1663 }
   1664 
   1665 bool ExtensionDownloadsEventRouter::DetermineFilename(
   1666     Profile* profile,
   1667     bool include_incognito,
   1668     const std::string& ext_id,
   1669     int download_id,
   1670     const base::FilePath& const_filename,
   1671     downloads::FilenameConflictAction conflict_action,
   1672     std::string* error) {
   1673   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1674   DownloadItem* item = GetDownload(profile, include_incognito, download_id);
   1675   ExtensionDownloadsEventRouterData* data =
   1676       item ? ExtensionDownloadsEventRouterData::Get(item) : NULL;
   1677   // maxListeners=1 in downloads.idl and suggestCallback in
   1678   // downloads_custom_bindings.js should prevent duplicate DeterminerCallback
   1679   // calls from the same renderer, but an extension may have more than one
   1680   // renderer, so don't DCHECK(!reported).
   1681   if (InvalidId(item, error) ||
   1682       Fault(item->GetState() != DownloadItem::IN_PROGRESS,
   1683             errors::kNotInProgress, error) ||
   1684       Fault(!data, errors::kUnexpectedDeterminer, error) ||
   1685       Fault(data->DeterminerAlreadyReported(ext_id),
   1686             errors::kTooManyListeners, error))
   1687     return false;
   1688   base::FilePath::StringType filename_str(const_filename.value());
   1689   // Allow windows-style directory separators on all platforms.
   1690   std::replace(filename_str.begin(), filename_str.end(),
   1691                FILE_PATH_LITERAL('\\'), FILE_PATH_LITERAL('/'));
   1692   base::FilePath filename(filename_str);
   1693   bool valid_filename = net::IsSafePortableRelativePath(filename);
   1694   filename = (valid_filename ? filename.NormalizePathSeparators() :
   1695               base::FilePath());
   1696   // If the invalid filename check is moved to before DeterminerCallback(), then
   1697   // it will block forever waiting for this ext_id to report.
   1698   if (Fault(!data->DeterminerCallback(
   1699                 profile, ext_id, filename, conflict_action),
   1700             errors::kUnexpectedDeterminer, error) ||
   1701       Fault((!const_filename.empty() && !valid_filename),
   1702             errors::kInvalidFilename, error))
   1703     return false;
   1704   return true;
   1705 }
   1706 
   1707 void ExtensionDownloadsEventRouter::OnListenerRemoved(
   1708     const extensions::EventListenerInfo& details) {
   1709   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1710   DownloadManager* manager = notifier_.GetManager();
   1711   if (!manager)
   1712     return;
   1713   bool determiner_removed = (
   1714       details.event_name == downloads::OnDeterminingFilename::kEventName);
   1715   extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
   1716       event_router();
   1717   bool any_listeners =
   1718     router->HasEventListener(downloads::OnChanged::kEventName) ||
   1719     router->HasEventListener(downloads::OnDeterminingFilename::kEventName);
   1720   if (!determiner_removed && any_listeners)
   1721     return;
   1722   DownloadManager::DownloadVector items;
   1723   manager->GetAllDownloads(&items);
   1724   for (DownloadManager::DownloadVector::const_iterator iter =
   1725        items.begin();
   1726        iter != items.end(); ++iter) {
   1727     ExtensionDownloadsEventRouterData* data =
   1728         ExtensionDownloadsEventRouterData::Get(*iter);
   1729     if (!data)
   1730       continue;
   1731     if (determiner_removed) {
   1732       // Notify any items that may be waiting for callbacks from this
   1733       // extension/determiner.  This will almost always be a no-op, however, it
   1734       // is possible for an extension renderer to be unloaded while a download
   1735       // item is waiting for a determiner. In that case, the download item
   1736       // should proceed.
   1737       data->DeterminerRemoved(details.extension_id);
   1738     }
   1739     if (!any_listeners &&
   1740         data->creator_suggested_filename().empty()) {
   1741       ExtensionDownloadsEventRouterData::Remove(*iter);
   1742     }
   1743   }
   1744 }
   1745 
   1746 // That's all the methods that have to do with filename determination. The rest
   1747 // have to do with the other, less special events.
   1748 
   1749 void ExtensionDownloadsEventRouter::OnDownloadCreated(
   1750     DownloadManager* manager, DownloadItem* download_item) {
   1751   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1752   if (download_item->IsTemporary())
   1753     return;
   1754 
   1755   extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
   1756       event_router();
   1757   // Avoid allocating a bunch of memory in DownloadItemToJSON if it isn't going
   1758   // to be used.
   1759   if (!router ||
   1760       (!router->HasEventListener(downloads::OnCreated::kEventName) &&
   1761        !router->HasEventListener(downloads::OnChanged::kEventName) &&
   1762        !router->HasEventListener(
   1763             downloads::OnDeterminingFilename::kEventName))) {
   1764     return;
   1765   }
   1766   scoped_ptr<base::DictionaryValue> json_item(
   1767       DownloadItemToJSON(download_item, profile_));
   1768   DispatchEvent(downloads::OnCreated::kEventName,
   1769                 true,
   1770                 extensions::Event::WillDispatchCallback(),
   1771                 json_item->DeepCopy());
   1772   if (!ExtensionDownloadsEventRouterData::Get(download_item) &&
   1773       (router->HasEventListener(downloads::OnChanged::kEventName) ||
   1774        router->HasEventListener(
   1775            downloads::OnDeterminingFilename::kEventName))) {
   1776     new ExtensionDownloadsEventRouterData(download_item, json_item.Pass());
   1777   }
   1778 }
   1779 
   1780 void ExtensionDownloadsEventRouter::OnDownloadUpdated(
   1781     DownloadManager* manager, DownloadItem* download_item) {
   1782   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1783   extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
   1784       event_router();
   1785   ExtensionDownloadsEventRouterData* data =
   1786     ExtensionDownloadsEventRouterData::Get(download_item);
   1787   if (download_item->IsTemporary() ||
   1788       !router->HasEventListener(downloads::OnChanged::kEventName)) {
   1789     return;
   1790   }
   1791   if (!data) {
   1792     // The download_item probably transitioned from temporary to not temporary,
   1793     // or else an event listener was added.
   1794     data = new ExtensionDownloadsEventRouterData(
   1795         download_item,
   1796         scoped_ptr<base::DictionaryValue>(new base::DictionaryValue()));
   1797   }
   1798   scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON(
   1799       download_item, profile_));
   1800   scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue());
   1801   delta->SetInteger(kIdKey, download_item->GetId());
   1802   std::set<std::string> new_fields;
   1803   bool changed = false;
   1804 
   1805   // For each field in the new json representation of the download_item except
   1806   // the bytesReceived field, if the field has changed from the previous old
   1807   // json, set the differences in the |delta| object and remember that something
   1808   // significant changed.
   1809   for (base::DictionaryValue::Iterator iter(*new_json.get());
   1810        !iter.IsAtEnd(); iter.Advance()) {
   1811     new_fields.insert(iter.key());
   1812     if (IsDownloadDeltaField(iter.key())) {
   1813       const base::Value* old_value = NULL;
   1814       if (!data->json().HasKey(iter.key()) ||
   1815           (data->json().Get(iter.key(), &old_value) &&
   1816            !iter.value().Equals(old_value))) {
   1817         delta->Set(iter.key() + ".current", iter.value().DeepCopy());
   1818         if (old_value)
   1819           delta->Set(iter.key() + ".previous", old_value->DeepCopy());
   1820         changed = true;
   1821       }
   1822     }
   1823   }
   1824 
   1825   // If a field was in the previous json but is not in the new json, set the
   1826   // difference in |delta|.
   1827   for (base::DictionaryValue::Iterator iter(data->json());
   1828        !iter.IsAtEnd(); iter.Advance()) {
   1829     if ((new_fields.find(iter.key()) == new_fields.end()) &&
   1830         IsDownloadDeltaField(iter.key())) {
   1831       // estimatedEndTime disappears after completion, but bytesReceived stays.
   1832       delta->Set(iter.key() + ".previous", iter.value().DeepCopy());
   1833       changed = true;
   1834     }
   1835   }
   1836 
   1837   // Update the OnChangedStat and dispatch the event if something significant
   1838   // changed. Replace the stored json with the new json.
   1839   data->OnItemUpdated();
   1840   if (changed) {
   1841     DispatchEvent(downloads::OnChanged::kEventName,
   1842                   true,
   1843                   extensions::Event::WillDispatchCallback(),
   1844                   delta.release());
   1845     data->OnChangedFired();
   1846   }
   1847   data->set_json(new_json.Pass());
   1848 }
   1849 
   1850 void ExtensionDownloadsEventRouter::OnDownloadRemoved(
   1851     DownloadManager* manager, DownloadItem* download_item) {
   1852   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1853   if (download_item->IsTemporary())
   1854     return;
   1855   DispatchEvent(downloads::OnErased::kEventName,
   1856                 true,
   1857                 extensions::Event::WillDispatchCallback(),
   1858                 new base::FundamentalValue(
   1859                     static_cast<int>(download_item->GetId())));
   1860 }
   1861 
   1862 void ExtensionDownloadsEventRouter::DispatchEvent(
   1863     const std::string& event_name,
   1864     bool include_incognito,
   1865     const extensions::Event::WillDispatchCallback& will_dispatch_callback,
   1866     base::Value* arg) {
   1867   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1868   if (!extensions::ExtensionSystem::Get(profile_)->event_router())
   1869     return;
   1870   scoped_ptr<base::ListValue> args(new base::ListValue());
   1871   args->Append(arg);
   1872   std::string json_args;
   1873   base::JSONWriter::Write(args.get(), &json_args);
   1874   scoped_ptr<extensions::Event> event(new extensions::Event(
   1875       event_name, args.Pass()));
   1876   // The downloads system wants to share on-record events with off-record
   1877   // extension renderers even in incognito_split_mode because that's how
   1878   // chrome://downloads works. The "restrict_to_profile" mechanism does not
   1879   // anticipate this, so it does not automatically prevent sharing off-record
   1880   // events with on-record extension renderers.
   1881   event->restrict_to_browser_context =
   1882       (include_incognito && !profile_->IsOffTheRecord()) ? NULL : profile_;
   1883   event->will_dispatch_callback = will_dispatch_callback;
   1884   extensions::ExtensionSystem::Get(profile_)->event_router()->
   1885       BroadcastEvent(event.Pass());
   1886   DownloadsNotificationSource notification_source;
   1887   notification_source.event_name = event_name;
   1888   notification_source.profile = profile_;
   1889   content::Source<DownloadsNotificationSource> content_source(
   1890       &notification_source);
   1891   content::NotificationService::current()->Notify(
   1892       chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT,
   1893       content_source,
   1894       content::Details<std::string>(&json_args));
   1895 }
   1896 
   1897 void ExtensionDownloadsEventRouter::Observe(
   1898     int type,
   1899     const content::NotificationSource& source,
   1900     const content::NotificationDetails& details) {
   1901   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1902   switch (type) {
   1903     case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
   1904       extensions::UnloadedExtensionInfo* unloaded =
   1905           content::Details<extensions::UnloadedExtensionInfo>(details).ptr();
   1906       std::set<const extensions::Extension*>::iterator iter =
   1907         shelf_disabling_extensions_.find(unloaded->extension);
   1908       if (iter != shelf_disabling_extensions_.end())
   1909         shelf_disabling_extensions_.erase(iter);
   1910       break;
   1911     }
   1912   }
   1913 }
   1914