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