Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Side by Side Diff: chrome/browser/extensions/api/downloads/downloads_api.cc

Issue 16924017: A few minor changes to the chrome.downloads extension API (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: @r213855 Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/downloads/downloads_api.h" 5 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cctype> 8 #include <cctype>
9 #include <iterator> 9 #include <iterator>
10 #include <set> 10 #include <set>
11 #include <string> 11 #include <string>
12 12
13 #include "base/basictypes.h" 13 #include "base/basictypes.h"
14 #include "base/bind.h" 14 #include "base/bind.h"
15 #include "base/bind_helpers.h" 15 #include "base/bind_helpers.h"
16 #include "base/callback.h" 16 #include "base/callback.h"
17 #include "base/file_util.h"
17 #include "base/files/file_path.h" 18 #include "base/files/file_path.h"
18 #include "base/json/json_writer.h" 19 #include "base/json/json_writer.h"
19 #include "base/lazy_instance.h" 20 #include "base/lazy_instance.h"
20 #include "base/logging.h" 21 #include "base/logging.h"
21 #include "base/memory/weak_ptr.h" 22 #include "base/memory/weak_ptr.h"
22 #include "base/metrics/histogram.h" 23 #include "base/metrics/histogram.h"
23 #include "base/stl_util.h" 24 #include "base/stl_util.h"
24 #include "base/strings/string16.h" 25 #include "base/strings/string16.h"
25 #include "base/strings/string_split.h" 26 #include "base/strings/string_split.h"
26 #include "base/strings/string_util.h" 27 #include "base/strings/string_util.h"
27 #include "base/strings/stringprintf.h" 28 #include "base/strings/stringprintf.h"
28 #include "base/values.h" 29 #include "base/values.h"
29 #include "chrome/browser/browser_process.h" 30 #include "chrome/browser/browser_process.h"
30 #include "chrome/browser/chrome_notification_types.h" 31 #include "chrome/browser/chrome_notification_types.h"
31 #include "chrome/browser/download/download_danger_prompt.h" 32 #include "chrome/browser/download/download_danger_prompt.h"
32 #include "chrome/browser/download/download_file_icon_extractor.h" 33 #include "chrome/browser/download/download_file_icon_extractor.h"
34 #include "chrome/browser/download/download_prefs.h"
33 #include "chrome/browser/download/download_query.h" 35 #include "chrome/browser/download/download_query.h"
34 #include "chrome/browser/download/download_service.h" 36 #include "chrome/browser/download/download_service.h"
35 #include "chrome/browser/download/download_service_factory.h" 37 #include "chrome/browser/download/download_service_factory.h"
38 #include "chrome/browser/download/download_shelf.h"
36 #include "chrome/browser/download/download_util.h" 39 #include "chrome/browser/download/download_util.h"
37 #include "chrome/browser/extensions/event_names.h" 40 #include "chrome/browser/extensions/event_names.h"
38 #include "chrome/browser/extensions/event_router.h" 41 #include "chrome/browser/extensions/event_router.h"
39 #include "chrome/browser/extensions/extension_function_dispatcher.h" 42 #include "chrome/browser/extensions/extension_function_dispatcher.h"
40 #include "chrome/browser/extensions/extension_info_map.h" 43 #include "chrome/browser/extensions/extension_info_map.h"
41 #include "chrome/browser/extensions/extension_prefs.h" 44 #include "chrome/browser/extensions/extension_prefs.h"
42 #include "chrome/browser/extensions/extension_service.h" 45 #include "chrome/browser/extensions/extension_service.h"
43 #include "chrome/browser/extensions/extension_system.h" 46 #include "chrome/browser/extensions/extension_system.h"
44 #include "chrome/browser/icon_loader.h" 47 #include "chrome/browser/icon_loader.h"
45 #include "chrome/browser/icon_manager.h" 48 #include "chrome/browser/icon_manager.h"
49 #include "chrome/browser/platform_util.h"
46 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" 50 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
47 #include "chrome/browser/ui/browser.h" 51 #include "chrome/browser/ui/browser.h"
52 #include "chrome/browser/ui/browser_window.h"
48 #include "chrome/common/cancelable_task_tracker.h" 53 #include "chrome/common/cancelable_task_tracker.h"
49 #include "chrome/common/extensions/api/downloads.h" 54 #include "chrome/common/extensions/api/downloads.h"
50 #include "chrome/common/extensions/permissions/permissions_data.h" 55 #include "chrome/common/extensions/permissions/permissions_data.h"
51 #include "content/public/browser/download_interrupt_reasons.h" 56 #include "content/public/browser/download_interrupt_reasons.h"
52 #include "content/public/browser/download_item.h" 57 #include "content/public/browser/download_item.h"
53 #include "content/public/browser/download_save_info.h" 58 #include "content/public/browser/download_save_info.h"
54 #include "content/public/browser/download_url_parameters.h" 59 #include "content/public/browser/download_url_parameters.h"
55 #include "content/public/browser/notification_service.h" 60 #include "content/public/browser/notification_service.h"
56 #include "content/public/browser/render_process_host.h" 61 #include "content/public/browser/render_process_host.h"
57 #include "content/public/browser/render_view_host.h" 62 #include "content/public/browser/render_view_host.h"
(...skipping 10 matching lines...) Expand all
68 73
69 namespace events = extensions::event_names; 74 namespace events = extensions::event_names;
70 75
71 using content::BrowserContext; 76 using content::BrowserContext;
72 using content::BrowserThread; 77 using content::BrowserThread;
73 using content::DownloadItem; 78 using content::DownloadItem;
74 using content::DownloadManager; 79 using content::DownloadManager;
75 80
76 namespace download_extension_errors { 81 namespace download_extension_errors {
77 82
78 // Error messages 83 const char kEmptyFile[] = "Filename not yet determined";
79 const char kGenericError[] = "I'm afraid I can't do that"; 84 const char kFileAlreadyDeleted[] = "Download file already deleted";
80 const char kIconNotFoundError[] = "Icon not found"; 85 const char kIconNotFound[] = "Icon not found";
81 const char kInvalidDangerTypeError[] = "Invalid danger type"; 86 const char kInvalidDangerType[] = "Invalid danger type";
82 const char kInvalidFilenameError[] = "Invalid filename"; 87 const char kInvalidFilename[] = "Invalid filename";
83 const char kInvalidFilterError[] = "Invalid query filter"; 88 const char kInvalidFilter[] = "Invalid query filter";
84 const char kInvalidOperationError[] = "Invalid operation"; 89 const char kInvalidHeader[] = "Invalid request header";
85 const char kInvalidOrderByError[] = "Invalid orderBy field"; 90 const char kInvalidId[] = "Invalid downloadId";
91 const char kInvalidOrderBy[] = "Invalid orderBy field";
86 const char kInvalidQueryLimit[] = "Invalid query limit"; 92 const char kInvalidQueryLimit[] = "Invalid query limit";
87 const char kInvalidStateError[] = "Invalid state"; 93 const char kInvalidState[] = "Invalid state";
88 const char kInvalidURLError[] = "Invalid URL"; 94 const char kInvalidURL[] = "Invalid URL";
89 const char kNotImplementedError[] = "NotImplemented"; 95 const char kInvisibleContext[] = "Javascript execution context is not visible "
90 const char kTooManyListenersError[] = "Each extension may have at most one " 96 "(tab, window, popup bubble)";
97 const char kNotComplete[] = "Download must be complete";
98 const char kNotDangerous[] = "Download must be dangerous";
99 const char kNotImplemented[] = "NotImplemented";
100 const char kNotInProgress[] = "Download must be in progress";
101 const char kNotPermittedURL[] = "In order to access that URL, this extension "
102 "must add the host to \"permissions\" in manifest.json";
103 const char kNotResumable[] = "DownloadItem.canResume must be true";
104 const char kOpenPermission[] = "The \"downloads.open\" permission is required";
105 const char kTooManyListeners[] = "Each extension may have at most one "
91 "onDeterminingFilename listener between all of its renderer execution " 106 "onDeterminingFilename listener between all of its renderer execution "
92 "contexts."; 107 "contexts.";
108 const char kUnexpectedDeterminer[] = "Unexpected determineFilename call";
93 109
94 } // namespace download_extension_errors 110 } // namespace download_extension_errors
95 111
112 namespace errors = download_extension_errors;
113
96 namespace { 114 namespace {
97 115
98 // Default icon size for getFileIcon() in pixels. 116 // Default icon size for getFileIcon() in pixels.
99 const int kDefaultIconSize = 32; 117 const int kDefaultIconSize = 32;
100 118
101 // Parameter keys 119 // Parameter keys
102 const char kBytesReceivedKey[] = "bytesReceived"; 120 const char kBytesReceivedKey[] = "bytesReceived";
103 const char kDangerAcceptedKey[] = "dangerAccepted"; 121 const char kCanResumeKey[] = "canResume";
122 const char kDangerAccepted[] = "accepted";
104 const char kDangerContent[] = "content"; 123 const char kDangerContent[] = "content";
105 const char kDangerFile[] = "file"; 124 const char kDangerFile[] = "file";
125 const char kDangerHost[] = "host";
106 const char kDangerKey[] = "danger"; 126 const char kDangerKey[] = "danger";
107 const char kDangerSafe[] = "safe"; 127 const char kDangerSafe[] = "safe";
108 const char kDangerUncommon[] = "uncommon"; 128 const char kDangerUncommon[] = "uncommon";
109 const char kDangerUnwanted[] = "unwanted"; 129 const char kDangerUnwanted[] = "unwanted";
110 const char kDangerAccepted[] = "accepted";
111 const char kDangerHost[] = "host";
112 const char kDangerUrl[] = "url"; 130 const char kDangerUrl[] = "url";
113 const char kEndTimeKey[] = "endTime"; 131 const char kEndTimeKey[] = "endTime";
114 const char kEndedAfterKey[] = "endedAfter"; 132 const char kEndedAfterKey[] = "endedAfter";
115 const char kEndedBeforeKey[] = "endedBefore"; 133 const char kEndedBeforeKey[] = "endedBefore";
116 const char kErrorKey[] = "error"; 134 const char kErrorKey[] = "error";
135 const char kEstimatedEndTimeKey[] = "estimatedEndTime";
117 const char kExistsKey[] = "exists"; 136 const char kExistsKey[] = "exists";
118 const char kFileSizeKey[] = "fileSize"; 137 const char kFileSizeKey[] = "fileSize";
119 const char kFilenameKey[] = "filename"; 138 const char kFilenameKey[] = "filename";
120 const char kFilenameRegexKey[] = "filenameRegex"; 139 const char kFilenameRegexKey[] = "filenameRegex";
121 const char kIdKey[] = "id"; 140 const char kIdKey[] = "id";
122 const char kIncognito[] = "incognito"; 141 const char kIncognitoKey[] = "incognito";
123 const char kMimeKey[] = "mime"; 142 const char kMimeKey[] = "mime";
124 const char kPausedKey[] = "paused"; 143 const char kPausedKey[] = "paused";
125 const char kQueryKey[] = "query"; 144 const char kQueryKey[] = "query";
145 const char kReferrerUrlKey[] = "referrer";
126 const char kStartTimeKey[] = "startTime"; 146 const char kStartTimeKey[] = "startTime";
127 const char kStartedAfterKey[] = "startedAfter"; 147 const char kStartedAfterKey[] = "startedAfter";
128 const char kStartedBeforeKey[] = "startedBefore"; 148 const char kStartedBeforeKey[] = "startedBefore";
129 const char kStateComplete[] = "complete"; 149 const char kStateComplete[] = "complete";
130 const char kStateInProgress[] = "in_progress"; 150 const char kStateInProgress[] = "in_progress";
131 const char kStateInterrupted[] = "interrupted"; 151 const char kStateInterrupted[] = "interrupted";
132 const char kStateKey[] = "state"; 152 const char kStateKey[] = "state";
133 const char kTotalBytesGreaterKey[] = "totalBytesGreater"; 153 const char kTotalBytesGreaterKey[] = "totalBytesGreater";
134 const char kTotalBytesKey[] = "totalBytes"; 154 const char kTotalBytesKey[] = "totalBytes";
135 const char kTotalBytesLessKey[] = "totalBytesLess"; 155 const char kTotalBytesLessKey[] = "totalBytesLess";
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 } 229 }
210 230
211 scoped_ptr<base::DictionaryValue> DownloadItemToJSON( 231 scoped_ptr<base::DictionaryValue> DownloadItemToJSON(
212 DownloadItem* download_item, 232 DownloadItem* download_item,
213 bool incognito) { 233 bool incognito) {
214 base::DictionaryValue* json = new base::DictionaryValue(); 234 base::DictionaryValue* json = new base::DictionaryValue();
215 json->SetBoolean(kExistsKey, !download_item->GetFileExternallyRemoved()); 235 json->SetBoolean(kExistsKey, !download_item->GetFileExternallyRemoved());
216 json->SetInteger(kIdKey, download_item->GetId()); 236 json->SetInteger(kIdKey, download_item->GetId());
217 const GURL& url = download_item->GetOriginalUrl(); 237 const GURL& url = download_item->GetOriginalUrl();
218 json->SetString(kUrlKey, (url.is_valid() ? url.spec() : std::string())); 238 json->SetString(kUrlKey, (url.is_valid() ? url.spec() : std::string()));
239 const GURL& referrer = download_item->GetReferrerUrl();
240 json->SetString(kReferrerUrlKey, (referrer.is_valid() ? referrer.spec()
241 : std::string()));
219 json->SetString(kFilenameKey, 242 json->SetString(kFilenameKey,
220 download_item->GetTargetFilePath().LossyDisplayName()); 243 download_item->GetTargetFilePath().LossyDisplayName());
221 json->SetString(kDangerKey, DangerString(download_item->GetDangerType())); 244 json->SetString(kDangerKey, DangerString(download_item->GetDangerType()));
222 if (download_item->GetDangerType() !=
223 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
224 json->SetBoolean(kDangerAcceptedKey,
225 download_item->GetDangerType() ==
226 content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED);
227 json->SetString(kStateKey, StateString(download_item->GetState())); 245 json->SetString(kStateKey, StateString(download_item->GetState()));
246 json->SetBoolean(kCanResumeKey, download_item->CanResume());
228 json->SetBoolean(kPausedKey, download_item->IsPaused()); 247 json->SetBoolean(kPausedKey, download_item->IsPaused());
229 json->SetString(kMimeKey, download_item->GetMimeType()); 248 json->SetString(kMimeKey, download_item->GetMimeType());
230 json->SetString(kStartTimeKey, TimeToISO8601(download_item->GetStartTime())); 249 json->SetString(kStartTimeKey, TimeToISO8601(download_item->GetStartTime()));
231 json->SetInteger(kBytesReceivedKey, download_item->GetReceivedBytes()); 250 json->SetInteger(kBytesReceivedKey, download_item->GetReceivedBytes());
232 json->SetInteger(kTotalBytesKey, download_item->GetTotalBytes()); 251 json->SetInteger(kTotalBytesKey, download_item->GetTotalBytes());
233 json->SetBoolean(kIncognito, incognito); 252 json->SetBoolean(kIncognitoKey, incognito);
234 if (download_item->GetState() == DownloadItem::INTERRUPTED) { 253 if (download_item->GetState() == DownloadItem::INTERRUPTED) {
235 json->SetInteger(kErrorKey, static_cast<int>( 254 json->SetString(kErrorKey, content::InterruptReasonDebugString(
236 download_item->GetLastReason())); 255 download_item->GetLastReason()));
237 } else if (download_item->GetState() == DownloadItem::CANCELLED) { 256 } else if (download_item->GetState() == DownloadItem::CANCELLED) {
238 json->SetInteger(kErrorKey, static_cast<int>( 257 json->SetString(kErrorKey, content::InterruptReasonDebugString(
239 content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED)); 258 content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED));
240 } 259 }
241 if (!download_item->GetEndTime().is_null()) 260 if (!download_item->GetEndTime().is_null())
242 json->SetString(kEndTimeKey, TimeToISO8601(download_item->GetEndTime())); 261 json->SetString(kEndTimeKey, TimeToISO8601(download_item->GetEndTime()));
262 base::TimeDelta time_remaining;
263 if (download_item->TimeRemaining(&time_remaining)) {
264 base::Time now = base::Time::Now();
265 json->SetString(kEstimatedEndTimeKey, TimeToISO8601(now + time_remaining));
266 }
243 // TODO(benjhayden): Implement fileSize. 267 // TODO(benjhayden): Implement fileSize.
244 json->SetInteger(kFileSizeKey, download_item->GetTotalBytes()); 268 json->SetInteger(kFileSizeKey, download_item->GetTotalBytes());
245 return scoped_ptr<base::DictionaryValue>(json); 269 return scoped_ptr<base::DictionaryValue>(json);
246 } 270 }
247 271
248 class DownloadFileIconExtractorImpl : public DownloadFileIconExtractor { 272 class DownloadFileIconExtractorImpl : public DownloadFileIconExtractor {
249 public: 273 public:
250 DownloadFileIconExtractorImpl() {} 274 DownloadFileIconExtractorImpl() {}
251 275
252 virtual ~DownloadFileIconExtractorImpl() {} 276 virtual ~DownloadFileIconExtractorImpl() {}
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 default: 317 default:
294 NOTREACHED(); 318 NOTREACHED();
295 return IconLoader::NORMAL; 319 return IconLoader::NORMAL;
296 } 320 }
297 } 321 }
298 322
299 typedef base::hash_map<std::string, DownloadQuery::FilterType> FilterTypeMap; 323 typedef base::hash_map<std::string, DownloadQuery::FilterType> FilterTypeMap;
300 324
301 void InitFilterTypeMap(FilterTypeMap& filter_types) { 325 void InitFilterTypeMap(FilterTypeMap& filter_types) {
302 filter_types[kBytesReceivedKey] = DownloadQuery::FILTER_BYTES_RECEIVED; 326 filter_types[kBytesReceivedKey] = DownloadQuery::FILTER_BYTES_RECEIVED;
303 filter_types[kDangerAcceptedKey] = DownloadQuery::FILTER_DANGER_ACCEPTED;
304 filter_types[kExistsKey] = DownloadQuery::FILTER_EXISTS; 327 filter_types[kExistsKey] = DownloadQuery::FILTER_EXISTS;
305 filter_types[kFilenameKey] = DownloadQuery::FILTER_FILENAME; 328 filter_types[kFilenameKey] = DownloadQuery::FILTER_FILENAME;
306 filter_types[kFilenameRegexKey] = DownloadQuery::FILTER_FILENAME_REGEX; 329 filter_types[kFilenameRegexKey] = DownloadQuery::FILTER_FILENAME_REGEX;
307 filter_types[kMimeKey] = DownloadQuery::FILTER_MIME; 330 filter_types[kMimeKey] = DownloadQuery::FILTER_MIME;
308 filter_types[kPausedKey] = DownloadQuery::FILTER_PAUSED; 331 filter_types[kPausedKey] = DownloadQuery::FILTER_PAUSED;
309 filter_types[kQueryKey] = DownloadQuery::FILTER_QUERY; 332 filter_types[kQueryKey] = DownloadQuery::FILTER_QUERY;
310 filter_types[kEndedAfterKey] = DownloadQuery::FILTER_ENDED_AFTER; 333 filter_types[kEndedAfterKey] = DownloadQuery::FILTER_ENDED_AFTER;
311 filter_types[kEndedBeforeKey] = DownloadQuery::FILTER_ENDED_BEFORE; 334 filter_types[kEndedBeforeKey] = DownloadQuery::FILTER_ENDED_BEFORE;
312 filter_types[kEndTimeKey] = DownloadQuery::FILTER_END_TIME; 335 filter_types[kEndTimeKey] = DownloadQuery::FILTER_END_TIME;
313 filter_types[kStartedAfterKey] = DownloadQuery::FILTER_STARTED_AFTER; 336 filter_types[kStartedAfterKey] = DownloadQuery::FILTER_STARTED_AFTER;
314 filter_types[kStartedBeforeKey] = DownloadQuery::FILTER_STARTED_BEFORE; 337 filter_types[kStartedBeforeKey] = DownloadQuery::FILTER_STARTED_BEFORE;
315 filter_types[kStartTimeKey] = DownloadQuery::FILTER_START_TIME; 338 filter_types[kStartTimeKey] = DownloadQuery::FILTER_START_TIME;
316 filter_types[kTotalBytesKey] = DownloadQuery::FILTER_TOTAL_BYTES; 339 filter_types[kTotalBytesKey] = DownloadQuery::FILTER_TOTAL_BYTES;
317 filter_types[kTotalBytesGreaterKey] = 340 filter_types[kTotalBytesGreaterKey] =
318 DownloadQuery::FILTER_TOTAL_BYTES_GREATER; 341 DownloadQuery::FILTER_TOTAL_BYTES_GREATER;
319 filter_types[kTotalBytesLessKey] = DownloadQuery::FILTER_TOTAL_BYTES_LESS; 342 filter_types[kTotalBytesLessKey] = DownloadQuery::FILTER_TOTAL_BYTES_LESS;
320 filter_types[kUrlKey] = DownloadQuery::FILTER_URL; 343 filter_types[kUrlKey] = DownloadQuery::FILTER_URL;
321 filter_types[kUrlRegexKey] = DownloadQuery::FILTER_URL_REGEX; 344 filter_types[kUrlRegexKey] = DownloadQuery::FILTER_URL_REGEX;
322 } 345 }
323 346
324 typedef base::hash_map<std::string, DownloadQuery::SortType> SortTypeMap; 347 typedef base::hash_map<std::string, DownloadQuery::SortType> SortTypeMap;
325 348
326 void InitSortTypeMap(SortTypeMap& sorter_types) { 349 void InitSortTypeMap(SortTypeMap& sorter_types) {
327 sorter_types[kBytesReceivedKey] = DownloadQuery::SORT_BYTES_RECEIVED; 350 sorter_types[kBytesReceivedKey] = DownloadQuery::SORT_BYTES_RECEIVED;
328 sorter_types[kDangerKey] = DownloadQuery::SORT_DANGER; 351 sorter_types[kDangerKey] = DownloadQuery::SORT_DANGER;
329 sorter_types[kDangerAcceptedKey] = DownloadQuery::SORT_DANGER_ACCEPTED;
330 sorter_types[kEndTimeKey] = DownloadQuery::SORT_END_TIME; 352 sorter_types[kEndTimeKey] = DownloadQuery::SORT_END_TIME;
331 sorter_types[kExistsKey] = DownloadQuery::SORT_EXISTS; 353 sorter_types[kExistsKey] = DownloadQuery::SORT_EXISTS;
332 sorter_types[kFilenameKey] = DownloadQuery::SORT_FILENAME; 354 sorter_types[kFilenameKey] = DownloadQuery::SORT_FILENAME;
333 sorter_types[kMimeKey] = DownloadQuery::SORT_MIME; 355 sorter_types[kMimeKey] = DownloadQuery::SORT_MIME;
334 sorter_types[kPausedKey] = DownloadQuery::SORT_PAUSED; 356 sorter_types[kPausedKey] = DownloadQuery::SORT_PAUSED;
335 sorter_types[kStartTimeKey] = DownloadQuery::SORT_START_TIME; 357 sorter_types[kStartTimeKey] = DownloadQuery::SORT_START_TIME;
336 sorter_types[kStateKey] = DownloadQuery::SORT_STATE; 358 sorter_types[kStateKey] = DownloadQuery::SORT_STATE;
337 sorter_types[kTotalBytesKey] = DownloadQuery::SORT_TOTAL_BYTES; 359 sorter_types[kTotalBytesKey] = DownloadQuery::SORT_TOTAL_BYTES;
338 sorter_types[kUrlKey] = DownloadQuery::SORT_URL; 360 sorter_types[kUrlKey] = DownloadQuery::SORT_URL;
339 } 361 }
(...skipping 25 matching lines...) Expand all
365 DownloadItem* GetDownload(Profile* profile, bool include_incognito, int id) { 387 DownloadItem* GetDownload(Profile* profile, bool include_incognito, int id) {
366 DownloadManager* manager = NULL; 388 DownloadManager* manager = NULL;
367 DownloadManager* incognito_manager = NULL; 389 DownloadManager* incognito_manager = NULL;
368 GetManagers(profile, include_incognito, &manager, &incognito_manager); 390 GetManagers(profile, include_incognito, &manager, &incognito_manager);
369 DownloadItem* download_item = manager->GetDownload(id); 391 DownloadItem* download_item = manager->GetDownload(id);
370 if (!download_item && incognito_manager) 392 if (!download_item && incognito_manager)
371 download_item = incognito_manager->GetDownload(id); 393 download_item = incognito_manager->GetDownload(id);
372 return download_item; 394 return download_item;
373 } 395 }
374 396
375 DownloadItem* GetDownloadIfInProgress(
376 Profile* profile,
377 bool include_incognito,
378 int id) {
379 DownloadItem* download_item = GetDownload(profile, include_incognito, id);
380 if (download_item && (download_item->GetState() == DownloadItem::IN_PROGRESS))
381 return download_item;
382 return NULL;
383 }
384
385 enum DownloadsFunctionName { 397 enum DownloadsFunctionName {
386 DOWNLOADS_FUNCTION_DOWNLOAD = 0, 398 DOWNLOADS_FUNCTION_DOWNLOAD = 0,
387 DOWNLOADS_FUNCTION_SEARCH = 1, 399 DOWNLOADS_FUNCTION_SEARCH = 1,
388 DOWNLOADS_FUNCTION_PAUSE = 2, 400 DOWNLOADS_FUNCTION_PAUSE = 2,
389 DOWNLOADS_FUNCTION_RESUME = 3, 401 DOWNLOADS_FUNCTION_RESUME = 3,
390 DOWNLOADS_FUNCTION_CANCEL = 4, 402 DOWNLOADS_FUNCTION_CANCEL = 4,
391 DOWNLOADS_FUNCTION_ERASE = 5, 403 DOWNLOADS_FUNCTION_ERASE = 5,
392 DOWNLOADS_FUNCTION_SET_DESTINATION = 6, 404 DOWNLOADS_FUNCTION_SET_DESTINATION = 6,
393 DOWNLOADS_FUNCTION_ACCEPT_DANGER = 7, 405 DOWNLOADS_FUNCTION_ACCEPT_DANGER = 7,
394 DOWNLOADS_FUNCTION_SHOW = 8, 406 DOWNLOADS_FUNCTION_SHOW = 8,
395 DOWNLOADS_FUNCTION_DRAG = 9, 407 DOWNLOADS_FUNCTION_DRAG = 9,
396 DOWNLOADS_FUNCTION_GET_FILE_ICON = 10, 408 DOWNLOADS_FUNCTION_GET_FILE_ICON = 10,
397 DOWNLOADS_FUNCTION_OPEN = 11, 409 DOWNLOADS_FUNCTION_OPEN = 11,
410 DOWNLOADS_FUNCTION_DELETE_FILE = 12,
411 DOWNLOADS_FUNCTION_SET_SHELF_VISIBLE = 13,
412 DOWNLOADS_FUNCTION_SHOW_DEFAULT_FOLDER = 14,
398 // Insert new values here, not at the beginning. 413 // Insert new values here, not at the beginning.
399 DOWNLOADS_FUNCTION_LAST 414 DOWNLOADS_FUNCTION_LAST
400 }; 415 };
401 416
402 void RecordApiFunctions(DownloadsFunctionName function) { 417 void RecordApiFunctions(DownloadsFunctionName function) {
403 UMA_HISTOGRAM_ENUMERATION("Download.ApiFunctions", 418 UMA_HISTOGRAM_ENUMERATION("Download.ApiFunctions",
404 function, 419 function,
405 DOWNLOADS_FUNCTION_LAST); 420 DOWNLOADS_FUNCTION_LAST);
406 } 421 }
407 422
408 void CompileDownloadQueryOrderBy( 423 void CompileDownloadQueryOrderBy(
409 const std::string& order_by_str, std::string* error, DownloadQuery* query) { 424 const std::vector<std::string>& order_by_strs,
425 std::string* error,
426 DownloadQuery* query) {
410 // TODO(benjhayden): Consider switching from LazyInstance to explicit string 427 // TODO(benjhayden): Consider switching from LazyInstance to explicit string
411 // comparisons. 428 // comparisons.
412 static base::LazyInstance<SortTypeMap> sorter_types = 429 static base::LazyInstance<SortTypeMap> sorter_types =
413 LAZY_INSTANCE_INITIALIZER; 430 LAZY_INSTANCE_INITIALIZER;
414 if (sorter_types.Get().size() == 0) 431 if (sorter_types.Get().size() == 0)
415 InitSortTypeMap(sorter_types.Get()); 432 InitSortTypeMap(sorter_types.Get());
416 433
417 std::vector<std::string> order_by_strs;
418 base::SplitString(order_by_str, ' ', &order_by_strs);
419 for (std::vector<std::string>::const_iterator iter = order_by_strs.begin(); 434 for (std::vector<std::string>::const_iterator iter = order_by_strs.begin();
420 iter != order_by_strs.end(); ++iter) { 435 iter != order_by_strs.end(); ++iter) {
421 std::string term_str = *iter; 436 std::string term_str = *iter;
422 if (term_str.empty()) 437 if (term_str.empty())
423 continue; 438 continue;
424 DownloadQuery::SortDirection direction = DownloadQuery::ASCENDING; 439 DownloadQuery::SortDirection direction = DownloadQuery::ASCENDING;
425 if (term_str[0] == '-') { 440 if (term_str[0] == '-') {
426 direction = DownloadQuery::DESCENDING; 441 direction = DownloadQuery::DESCENDING;
427 term_str = term_str.substr(1); 442 term_str = term_str.substr(1);
428 } 443 }
429 SortTypeMap::const_iterator sorter_type = 444 SortTypeMap::const_iterator sorter_type =
430 sorter_types.Get().find(term_str); 445 sorter_types.Get().find(term_str);
431 if (sorter_type == sorter_types.Get().end()) { 446 if (sorter_type == sorter_types.Get().end()) {
432 *error = download_extension_errors::kInvalidOrderByError; 447 *error = errors::kInvalidOrderBy;
433 return; 448 return;
434 } 449 }
435 query->AddSorter(sorter_type->second, direction); 450 query->AddSorter(sorter_type->second, direction);
436 } 451 }
437 } 452 }
438 453
439 void RunDownloadQuery( 454 void RunDownloadQuery(
440 const extensions::api::downloads::DownloadQuery& query_in, 455 const extensions::api::downloads::DownloadQuery& query_in,
441 DownloadManager* manager, 456 DownloadManager* manager,
442 DownloadManager* incognito_manager, 457 DownloadManager* incognito_manager,
443 std::string* error, 458 std::string* error,
444 DownloadQuery::DownloadVector* results) { 459 DownloadQuery::DownloadVector* results) {
445 // TODO(benjhayden): Consider switching from LazyInstance to explicit string 460 // TODO(benjhayden): Consider switching from LazyInstance to explicit string
446 // comparisons. 461 // comparisons.
447 static base::LazyInstance<FilterTypeMap> filter_types = 462 static base::LazyInstance<FilterTypeMap> filter_types =
448 LAZY_INSTANCE_INITIALIZER; 463 LAZY_INSTANCE_INITIALIZER;
449 if (filter_types.Get().size() == 0) 464 if (filter_types.Get().size() == 0)
450 InitFilterTypeMap(filter_types.Get()); 465 InitFilterTypeMap(filter_types.Get());
451 466
452 DownloadQuery query_out; 467 DownloadQuery query_out;
453 468
469 size_t limit = 1000;
454 if (query_in.limit.get()) { 470 if (query_in.limit.get()) {
455 if (*query_in.limit.get() < 0) { 471 if (*query_in.limit.get() < 0) {
456 *error = download_extension_errors::kInvalidQueryLimit; 472 *error = errors::kInvalidQueryLimit;
457 return; 473 return;
458 } 474 }
459 query_out.Limit(*query_in.limit.get()); 475 limit = *query_in.limit.get();
460 } 476 }
477 if (limit > 0) {
478 query_out.Limit(limit);
479 }
480
461 std::string state_string = 481 std::string state_string =
462 extensions::api::downloads::ToString(query_in.state); 482 extensions::api::downloads::ToString(query_in.state);
463 if (!state_string.empty()) { 483 if (!state_string.empty()) {
464 DownloadItem::DownloadState state = StateEnumFromString(state_string); 484 DownloadItem::DownloadState state = StateEnumFromString(state_string);
465 if (state == DownloadItem::MAX_DOWNLOAD_STATE) { 485 if (state == DownloadItem::MAX_DOWNLOAD_STATE) {
466 *error = download_extension_errors::kInvalidStateError; 486 *error = errors::kInvalidState;
467 return; 487 return;
468 } 488 }
469 query_out.AddFilter(state); 489 query_out.AddFilter(state);
470 } 490 }
471 std::string danger_string = 491 std::string danger_string =
472 extensions::api::downloads::ToString(query_in.danger); 492 extensions::api::downloads::ToString(query_in.danger);
473 if (!danger_string.empty()) { 493 if (!danger_string.empty()) {
474 content::DownloadDangerType danger_type = DangerEnumFromString( 494 content::DownloadDangerType danger_type = DangerEnumFromString(
475 danger_string); 495 danger_string);
476 if (danger_type == content::DOWNLOAD_DANGER_TYPE_MAX) { 496 if (danger_type == content::DOWNLOAD_DANGER_TYPE_MAX) {
477 *error = download_extension_errors::kInvalidDangerTypeError; 497 *error = errors::kInvalidDangerType;
478 return; 498 return;
479 } 499 }
480 query_out.AddFilter(danger_type); 500 query_out.AddFilter(danger_type);
481 } 501 }
482 if (query_in.order_by.get()) { 502 if (query_in.order_by.get()) {
483 CompileDownloadQueryOrderBy(*query_in.order_by.get(), error, &query_out); 503 CompileDownloadQueryOrderBy(*query_in.order_by.get(), error, &query_out);
484 if (!error->empty()) 504 if (!error->empty())
485 return; 505 return;
486 } 506 }
487 507
488 scoped_ptr<base::DictionaryValue> query_in_value(query_in.ToValue().Pass()); 508 scoped_ptr<base::DictionaryValue> query_in_value(query_in.ToValue().Pass());
489 for (base::DictionaryValue::Iterator query_json_field(*query_in_value.get()); 509 for (base::DictionaryValue::Iterator query_json_field(*query_in_value.get());
490 !query_json_field.IsAtEnd(); query_json_field.Advance()) { 510 !query_json_field.IsAtEnd(); query_json_field.Advance()) {
491 FilterTypeMap::const_iterator filter_type = 511 FilterTypeMap::const_iterator filter_type =
492 filter_types.Get().find(query_json_field.key()); 512 filter_types.Get().find(query_json_field.key());
493 if (filter_type != filter_types.Get().end()) { 513 if (filter_type != filter_types.Get().end()) {
494 if (!query_out.AddFilter(filter_type->second, query_json_field.value())) { 514 if (!query_out.AddFilter(filter_type->second, query_json_field.value())) {
495 *error = download_extension_errors::kInvalidFilterError; 515 *error = errors::kInvalidFilter;
496 return; 516 return;
497 } 517 }
498 } 518 }
499 } 519 }
500 520
501 DownloadQuery::DownloadVector all_items; 521 DownloadQuery::DownloadVector all_items;
502 if (query_in.id.get()) { 522 if (query_in.id.get()) {
503 DownloadItem* download_item = manager->GetDownload(*query_in.id.get()); 523 DownloadItem* download_item = manager->GetDownload(*query_in.id.get());
504 if (!download_item && incognito_manager) 524 if (!download_item && incognito_manager)
505 download_item = incognito_manager->GetDownload(*query_in.id.get()); 525 download_item = incognito_manager->GetDownload(*query_in.id.get());
506 if (download_item) 526 if (download_item)
507 all_items.push_back(download_item); 527 all_items.push_back(download_item);
508 } else { 528 } else {
509 manager->GetAllDownloads(&all_items); 529 manager->GetAllDownloads(&all_items);
510 if (incognito_manager) 530 if (incognito_manager)
511 incognito_manager->GetAllDownloads(&all_items); 531 incognito_manager->GetAllDownloads(&all_items);
512 } 532 }
513 query_out.AddFilter(base::Bind(&IsNotTemporaryDownloadFilter)); 533 query_out.AddFilter(base::Bind(&IsNotTemporaryDownloadFilter));
514 query_out.Search(all_items.begin(), all_items.end(), results); 534 query_out.Search(all_items.begin(), all_items.end(), results);
515 } 535 }
516 536
537 DownloadPathReservationTracker::FilenameConflictAction ConvertConflictAction(
538 extensions::api::downloads::FilenameConflictAction action) {
539 switch (action) {
540 case extensions::api::downloads::FILENAME_CONFLICT_ACTION_NONE:
541 case extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY:
542 return DownloadPathReservationTracker::UNIQUIFY;
543 case extensions::api::downloads::FILENAME_CONFLICT_ACTION_OVERWRITE:
544 return DownloadPathReservationTracker::OVERWRITE;
545 case extensions::api::downloads::FILENAME_CONFLICT_ACTION_PROMPT:
546 return DownloadPathReservationTracker::PROMPT;
547 }
548 NOTREACHED();
549 return DownloadPathReservationTracker::UNIQUIFY;
550 }
551
517 class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data { 552 class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data {
518 public: 553 public:
519 static ExtensionDownloadsEventRouterData* Get(DownloadItem* download_item) { 554 static ExtensionDownloadsEventRouterData* Get(DownloadItem* download_item) {
520 base::SupportsUserData::Data* data = download_item->GetUserData(kKey); 555 base::SupportsUserData::Data* data = download_item->GetUserData(kKey);
521 return (data == NULL) ? NULL : 556 return (data == NULL) ? NULL :
522 static_cast<ExtensionDownloadsEventRouterData*>(data); 557 static_cast<ExtensionDownloadsEventRouterData*>(data);
523 } 558 }
524 559
525 static void Remove(DownloadItem* download_item) { 560 static void Remove(DownloadItem* download_item) {
526 download_item->RemoveUserData(kKey); 561 download_item->RemoveUserData(kKey);
527 } 562 }
528 563
529 explicit ExtensionDownloadsEventRouterData( 564 explicit ExtensionDownloadsEventRouterData(
530 DownloadItem* download_item, 565 DownloadItem* download_item,
531 scoped_ptr<base::DictionaryValue> json_item) 566 scoped_ptr<base::DictionaryValue> json_item)
532 : updated_(0), 567 : updated_(0),
533 changed_fired_(0), 568 changed_fired_(0),
534 json_(json_item.Pass()), 569 json_(json_item.Pass()),
570 creator_conflict_action_(
571 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY),
535 determined_conflict_action_( 572 determined_conflict_action_(
536 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) { 573 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) {
537 download_item->SetUserData(kKey, this); 574 download_item->SetUserData(kKey, this);
538 } 575 }
539 576
540 virtual ~ExtensionDownloadsEventRouterData() { 577 virtual ~ExtensionDownloadsEventRouterData() {
541 if (updated_ > 0) { 578 if (updated_ > 0) {
542 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", 579 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged",
543 (changed_fired_ * 100 / updated_)); 580 (changed_fired_ * 100 / updated_));
544 } 581 }
545 } 582 }
546 583
547 const base::DictionaryValue& json() const { return *json_.get(); } 584 const base::DictionaryValue& json() const { return *json_.get(); }
548 void set_json(scoped_ptr<base::DictionaryValue> json_item) { 585 void set_json(scoped_ptr<base::DictionaryValue> json_item) {
549 json_ = json_item.Pass(); 586 json_ = json_item.Pass();
550 } 587 }
551 588
552 void OnItemUpdated() { ++updated_; } 589 void OnItemUpdated() { ++updated_; }
553 void OnChangedFired() { ++changed_fired_; } 590 void OnChangedFired() { ++changed_fired_; }
554 591
555 void set_filename_change_callbacks( 592 void set_filename_change_callbacks(
556 const base::Closure& no_change, 593 const base::Closure& no_change,
557 const ExtensionDownloadsEventRouter::FilenameChangedCallback& change) { 594 const ExtensionDownloadsEventRouter::FilenameChangedCallback& change) {
558 filename_no_change_ = no_change; 595 filename_no_change_ = no_change;
559 filename_change_ = change; 596 filename_change_ = change;
597 determined_filename_ = creator_suggested_filename_;
598 determined_conflict_action_ = creator_conflict_action_;
599 // determiner_.install_time should default to 0 so that creator suggestions
600 // should be lower priority than any actual onDeterminingFilename listeners.
560 } 601 }
561 602
562 void ClearPendingDeterminers() { 603 void ClearPendingDeterminers() {
563 determined_filename_.clear(); 604 determined_filename_.clear();
564 determined_conflict_action_ = 605 determined_conflict_action_ =
565 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY; 606 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY;
566 determiner_ = DeterminerInfo(); 607 determiner_ = DeterminerInfo();
567 filename_no_change_ = base::Closure(); 608 filename_no_change_ = base::Closure();
568 filename_change_ = ExtensionDownloadsEventRouter::FilenameChangedCallback(); 609 filename_change_ = ExtensionDownloadsEventRouter::FilenameChangedCallback();
569 weak_ptr_factory_.reset(); 610 weak_ptr_factory_.reset();
(...skipping 27 matching lines...) Expand all
597 638
598 bool DeterminerAlreadyReported(const std::string& extension_id) { 639 bool DeterminerAlreadyReported(const std::string& extension_id) {
599 for (size_t index = 0; index < determiners_.size(); ++index) { 640 for (size_t index = 0; index < determiners_.size(); ++index) {
600 if (determiners_[index].extension_id == extension_id) { 641 if (determiners_[index].extension_id == extension_id) {
601 return determiners_[index].reported; 642 return determiners_[index].reported;
602 } 643 }
603 } 644 }
604 return false; 645 return false;
605 } 646 }
606 647
648 void CreatorSuggestedFilename(
649 const base::FilePath& filename,
650 extensions::api::downloads::FilenameConflictAction conflict_action) {
651 creator_suggested_filename_ = filename;
652 creator_conflict_action_ = conflict_action;
653 }
654
655 base::FilePath creator_suggested_filename() const {
656 return creator_suggested_filename_;
657 }
658
659 extensions::api::downloads::FilenameConflictAction
660 creator_conflict_action() const {
661 return creator_conflict_action_;
662 }
663
664 void ResetCreatorSuggestion() {
665 creator_suggested_filename_.clear();
666 creator_conflict_action_ =
667 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY;
668 }
669
607 // Returns false if this |extension_id| was not expected or if this 670 // Returns false if this |extension_id| was not expected or if this
608 // |extension_id| has already reported. The caller is responsible for 671 // |extension_id| has already reported. The caller is responsible for
609 // validating |filename|. 672 // validating |filename|.
610 bool DeterminerCallback( 673 bool DeterminerCallback(
611 const std::string& extension_id, 674 const std::string& extension_id,
612 const base::FilePath& filename, 675 const base::FilePath& filename,
613 extensions::api::downloads::FilenameConflictAction conflict_action) { 676 extensions::api::downloads::FilenameConflictAction conflict_action) {
614 bool found_info = false; 677 bool found_info = false;
615 for (size_t index = 0; index < determiners_.size(); ++index) { 678 for (size_t index = 0; index < determiners_.size(); ++index) {
616 if (determiners_[index].extension_id == extension_id) { 679 if (determiners_[index].extension_id == extension_id) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 for (DeterminerInfoVector::iterator iter = determiners_.begin(); 721 for (DeterminerInfoVector::iterator iter = determiners_.begin();
659 iter != determiners_.end(); ++iter) { 722 iter != determiners_.end(); ++iter) {
660 if (!iter->reported) 723 if (!iter->reported)
661 return; 724 return;
662 } 725 }
663 if (determined_filename_.empty()) { 726 if (determined_filename_.empty()) {
664 if (!filename_no_change_.is_null()) 727 if (!filename_no_change_.is_null())
665 filename_no_change_.Run(); 728 filename_no_change_.Run();
666 } else { 729 } else {
667 if (!filename_change_.is_null()) { 730 if (!filename_change_.is_null()) {
668 DownloadPathReservationTracker::FilenameConflictAction conflict_action = 731 filename_change_.Run(determined_filename_, ConvertConflictAction(
669 DownloadPathReservationTracker::UNIQUIFY; 732 determined_conflict_action_));
670 if (determined_conflict_action_ ==
671 extensions::api::downloads::FILENAME_CONFLICT_ACTION_OVERWRITE)
672 conflict_action = DownloadPathReservationTracker::OVERWRITE;
673 if (determined_conflict_action_ ==
674 extensions::api::downloads::FILENAME_CONFLICT_ACTION_PROMPT)
675 conflict_action = DownloadPathReservationTracker::PROMPT;
676 filename_change_.Run(determined_filename_, conflict_action);
677 } 733 }
678 } 734 }
679 // Don't clear determiners_ immediately in case there's a second listener 735 // Don't clear determiners_ immediately in case there's a second listener
680 // for one of the extensions, so that DetermineFilename can return 736 // for one of the extensions, so that DetermineFilename can return
681 // kTooManyListenersError. After a few seconds, DetermineFilename will 737 // kTooManyListeners. After a few seconds, DetermineFilename will return
682 // return kInvalidOperationError instead of kTooManyListenersError so that 738 // kUnexpectedDeterminer instead of kTooManyListeners so that determiners_
683 // determiners_ doesn't keep hogging memory. 739 // doesn't keep hogging memory.
684 weak_ptr_factory_.reset( 740 weak_ptr_factory_.reset(
685 new base::WeakPtrFactory<ExtensionDownloadsEventRouterData>(this)); 741 new base::WeakPtrFactory<ExtensionDownloadsEventRouterData>(this));
686 base::MessageLoopForUI::current()->PostDelayedTask( 742 base::MessageLoopForUI::current()->PostDelayedTask(
687 FROM_HERE, 743 FROM_HERE,
688 base::Bind(&ExtensionDownloadsEventRouterData::ClearPendingDeterminers, 744 base::Bind(&ExtensionDownloadsEventRouterData::ClearPendingDeterminers,
689 weak_ptr_factory_->GetWeakPtr()), 745 weak_ptr_factory_->GetWeakPtr()),
690 base::TimeDelta::FromSeconds(30)); 746 base::TimeDelta::FromSeconds(30));
691 } 747 }
692 748
693 int updated_; 749 int updated_;
694 int changed_fired_; 750 int changed_fired_;
695 scoped_ptr<base::DictionaryValue> json_; 751 scoped_ptr<base::DictionaryValue> json_;
696 752
697 base::Closure filename_no_change_; 753 base::Closure filename_no_change_;
698 ExtensionDownloadsEventRouter::FilenameChangedCallback filename_change_; 754 ExtensionDownloadsEventRouter::FilenameChangedCallback filename_change_;
699 755
700 DeterminerInfoVector determiners_; 756 DeterminerInfoVector determiners_;
701 757
758 base::FilePath creator_suggested_filename_;
759 extensions::api::downloads::FilenameConflictAction
760 creator_conflict_action_;
702 base::FilePath determined_filename_; 761 base::FilePath determined_filename_;
703 extensions::api::downloads::FilenameConflictAction 762 extensions::api::downloads::FilenameConflictAction
704 determined_conflict_action_; 763 determined_conflict_action_;
705 DeterminerInfo determiner_; 764 DeterminerInfo determiner_;
706 765
707 scoped_ptr<base::WeakPtrFactory<ExtensionDownloadsEventRouterData> > 766 scoped_ptr<base::WeakPtrFactory<ExtensionDownloadsEventRouterData> >
708 weak_ptr_factory_; 767 weak_ptr_factory_;
709 768
710 DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouterData); 769 DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouterData);
711 }; 770 };
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 Profile* profile, 848 Profile* profile,
790 const extensions::Extension* extension, 849 const extensions::Extension* extension,
791 base::ListValue* event_args) { 850 base::ListValue* event_args) {
792 *any_determiners = true; 851 *any_determiners = true;
793 base::Time installed = extensions::ExtensionSystem::Get( 852 base::Time installed = extensions::ExtensionSystem::Get(
794 profile)->extension_service()->extension_prefs()-> 853 profile)->extension_service()->extension_prefs()->
795 GetInstallTime(extension->id()); 854 GetInstallTime(extension->id());
796 data->AddPendingDeterminer(extension->id(), installed); 855 data->AddPendingDeterminer(extension->id(), installed);
797 } 856 }
798 857
858 bool Fault(bool error,
859 const char* message_in,
860 std::string* message_out) {
861 if (!error)
862 return false;
863 *message_out = message_in;
864 return true;
865 }
866
867 bool InvalidId(DownloadItem* valid_item, std::string* message_out) {
868 return Fault(!valid_item, errors::kInvalidId, message_out);
869 }
870
871 bool IsDownloadDeltaField(const std::string& field) {
872 return ((field == kUrlKey) ||
873 (field == kFilenameKey) ||
874 (field == kDangerKey) ||
875 (field == kMimeKey) ||
876 (field == kStartTimeKey) ||
877 (field == kEndTimeKey) ||
878 (field == kStateKey) ||
879 (field == kCanResumeKey) ||
880 (field == kPausedKey) ||
881 (field == kErrorKey) ||
882 (field == kTotalBytesKey) ||
883 (field == kFileSizeKey) ||
884 (field == kExistsKey));
885 }
886
799 } // namespace 887 } // namespace
800 888
801 DownloadsDownloadFunction::DownloadsDownloadFunction() {} 889 DownloadsDownloadFunction::DownloadsDownloadFunction() {}
802 890
803 DownloadsDownloadFunction::~DownloadsDownloadFunction() {} 891 DownloadsDownloadFunction::~DownloadsDownloadFunction() {}
804 892
805 bool DownloadsDownloadFunction::RunImpl() { 893 bool DownloadsDownloadFunction::RunImpl() {
806 scoped_ptr<extensions::api::downloads::Download::Params> params( 894 scoped_ptr<extensions::api::downloads::Download::Params> params(
807 extensions::api::downloads::Download::Params::Create(*args_)); 895 extensions::api::downloads::Download::Params::Create(*args_));
808 EXTENSION_FUNCTION_VALIDATE(params.get()); 896 EXTENSION_FUNCTION_VALIDATE(params.get());
809 const extensions::api::downloads::DownloadOptions& options = params->options; 897 const extensions::api::downloads::DownloadOptions& options = params->options;
810 GURL download_url(options.url); 898 GURL download_url(options.url);
811 if (!download_url.is_valid()) { 899 if (Fault(!download_url.is_valid(), errors::kInvalidURL, &error_))
812 error_ = download_extension_errors::kInvalidURLError;
813 return false; 900 return false;
814 }
815 901
816 Profile* current_profile = profile(); 902 Profile* current_profile = profile();
817 if (include_incognito() && profile()->HasOffTheRecordProfile()) 903 if (include_incognito() && profile()->HasOffTheRecordProfile())
818 current_profile = profile()->GetOffTheRecordProfile(); 904 current_profile = profile()->GetOffTheRecordProfile();
819 905
820 scoped_ptr<content::DownloadUrlParameters> download_params( 906 scoped_ptr<content::DownloadUrlParameters> download_params(
821 new content::DownloadUrlParameters( 907 new content::DownloadUrlParameters(
822 download_url, 908 download_url,
823 render_view_host()->GetProcess()->GetID(), 909 render_view_host()->GetProcess()->GetID(),
824 render_view_host()->GetRoutingID(), 910 render_view_host()->GetRoutingID(),
825 current_profile->GetResourceContext())); 911 current_profile->GetResourceContext()));
826 912
913 base::FilePath creator_suggested_filename;
827 if (options.filename.get()) { 914 if (options.filename.get()) {
828 // TODO(benjhayden): Make json_schema_compiler generate string16s instead of 915 #if defined(OS_WIN)
829 // std::strings. Can't get filename16 from options.ToValue() because that 916 // Can't get filename16 from options.ToValue() because that converts it from
830 // converts it from std::string. 917 // std::string.
831 base::DictionaryValue* options_value = NULL; 918 base::DictionaryValue* options_value = NULL;
832 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_value)); 919 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_value));
833 string16 filename16; 920 base::string16 filename16;
834 EXTENSION_FUNCTION_VALIDATE(options_value->GetString( 921 EXTENSION_FUNCTION_VALIDATE(options_value->GetString(
835 kFilenameKey, &filename16)); 922 kFilenameKey, &filename16));
836 #if defined(OS_WIN) 923 creator_suggested_filename = base::FilePath(filename16);
837 base::FilePath file_path(filename16);
838 #elif defined(OS_POSIX) 924 #elif defined(OS_POSIX)
839 base::FilePath file_path(*options.filename.get()); 925 creator_suggested_filename = base::FilePath(*options.filename.get());
840 #endif 926 #endif
841 if (!net::IsSafePortableBasename(file_path) || 927 if (!net::IsSafePortableRelativePath(creator_suggested_filename)) {
842 (file_path.DirName().value() != base::FilePath::kCurrentDirectory)) { 928 error_ = errors::kInvalidFilename;
843 error_ = download_extension_errors::kInvalidFilenameError;
844 return false; 929 return false;
845 } 930 }
846 // TODO(benjhayden) Ensure that this filename is interpreted as a path
847 // relative to the default downloads directory without allowing '..'.
848 download_params->set_suggested_name(filename16);
849 } 931 }
850 932
851 if (options.save_as.get()) 933 if (options.save_as.get())
852 download_params->set_prompt(*options.save_as.get()); 934 download_params->set_prompt(*options.save_as.get());
853 935
854 if (options.headers.get()) { 936 if (options.headers.get()) {
855 typedef extensions::api::downloads::HeaderNameValuePair HeaderNameValuePair; 937 typedef extensions::api::downloads::HeaderNameValuePair HeaderNameValuePair;
856 for (std::vector<linked_ptr<HeaderNameValuePair> >::const_iterator iter = 938 for (std::vector<linked_ptr<HeaderNameValuePair> >::const_iterator iter =
857 options.headers->begin(); 939 options.headers->begin();
858 iter != options.headers->end(); 940 iter != options.headers->end();
859 ++iter) { 941 ++iter) {
860 const HeaderNameValuePair& name_value = **iter; 942 const HeaderNameValuePair& name_value = **iter;
861 if (!net::HttpUtil::IsSafeHeader(name_value.name)) { 943 if (!net::HttpUtil::IsSafeHeader(name_value.name)) {
862 error_ = download_extension_errors::kGenericError; 944 error_ = errors::kInvalidHeader;
863 return false; 945 return false;
864 } 946 }
865 download_params->add_request_header(name_value.name, name_value.value); 947 download_params->add_request_header(name_value.name, name_value.value);
866 } 948 }
867 } 949 }
868 950
869 std::string method_string = 951 std::string method_string =
870 extensions::api::downloads::ToString(options.method); 952 extensions::api::downloads::ToString(options.method);
871 if (!method_string.empty()) 953 if (!method_string.empty())
872 download_params->set_method(method_string); 954 download_params->set_method(method_string);
873 if (options.body.get()) 955 if (options.body.get())
874 download_params->set_post_body(*options.body.get()); 956 download_params->set_post_body(*options.body.get());
875 download_params->set_callback(base::Bind( 957 download_params->set_callback(base::Bind(
876 &DownloadsDownloadFunction::OnStarted, this)); 958 &DownloadsDownloadFunction::OnStarted, this,
959 creator_suggested_filename, options.conflict_action));
877 // Prevent login prompts for 401/407 responses. 960 // Prevent login prompts for 401/407 responses.
878 download_params->set_load_flags(net::LOAD_DO_NOT_PROMPT_FOR_LOGIN); 961 download_params->set_load_flags(net::LOAD_DO_NOT_PROMPT_FOR_LOGIN);
879 962
880 DownloadManager* manager = BrowserContext::GetDownloadManager( 963 DownloadManager* manager = BrowserContext::GetDownloadManager(
881 current_profile); 964 current_profile);
882 manager->DownloadUrl(download_params.Pass()); 965 manager->DownloadUrl(download_params.Pass());
966 download_util::RecordDownloadSource(download_util::INITIATED_BY_EXTENSION);
883 RecordApiFunctions(DOWNLOADS_FUNCTION_DOWNLOAD); 967 RecordApiFunctions(DOWNLOADS_FUNCTION_DOWNLOAD);
884 return true; 968 return true;
885 } 969 }
886 970
887 void DownloadsDownloadFunction::OnStarted( 971 void DownloadsDownloadFunction::OnStarted(
888 DownloadItem* item, net::Error error) { 972 const base::FilePath& creator_suggested_filename,
973 extensions::api::downloads::FilenameConflictAction creator_conflict_action,
974 DownloadItem* item,
975 net::Error error) {
889 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 976 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
890 VLOG(1) << __FUNCTION__ << " " << item << " " << error; 977 VLOG(1) << __FUNCTION__ << " " << item << " " << error;
891 if (item) { 978 if (item) {
892 DCHECK_EQ(net::OK, error); 979 DCHECK_EQ(net::OK, error);
893 SetResult(base::Value::CreateIntegerValue(item->GetId())); 980 SetResult(base::Value::CreateIntegerValue(item->GetId()));
981 if (!creator_suggested_filename.empty()) {
982 ExtensionDownloadsEventRouterData* data =
983 ExtensionDownloadsEventRouterData::Get(item);
984 if (!data) {
985 data = new ExtensionDownloadsEventRouterData(
986 item,
987 scoped_ptr<base::DictionaryValue>(new base::DictionaryValue()));
988 }
989 data->CreatorSuggestedFilename(
990 creator_suggested_filename, creator_conflict_action);
991 }
894 } else { 992 } else {
895 DCHECK_NE(net::OK, error); 993 DCHECK_NE(net::OK, error);
896 error_ = net::ErrorToString(error); 994 error_ = net::ErrorToString(error);
897 } 995 }
898 SendResponse(error_.empty()); 996 SendResponse(error_.empty());
899 } 997 }
900 998
901 DownloadsSearchFunction::DownloadsSearchFunction() {} 999 DownloadsSearchFunction::DownloadsSearchFunction() {}
902 1000
903 DownloadsSearchFunction::~DownloadsSearchFunction() {} 1001 DownloadsSearchFunction::~DownloadsSearchFunction() {}
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
937 } 1035 }
938 1036
939 DownloadsPauseFunction::DownloadsPauseFunction() {} 1037 DownloadsPauseFunction::DownloadsPauseFunction() {}
940 1038
941 DownloadsPauseFunction::~DownloadsPauseFunction() {} 1039 DownloadsPauseFunction::~DownloadsPauseFunction() {}
942 1040
943 bool DownloadsPauseFunction::RunImpl() { 1041 bool DownloadsPauseFunction::RunImpl() {
944 scoped_ptr<extensions::api::downloads::Pause::Params> params( 1042 scoped_ptr<extensions::api::downloads::Pause::Params> params(
945 extensions::api::downloads::Pause::Params::Create(*args_)); 1043 extensions::api::downloads::Pause::Params::Create(*args_));
946 EXTENSION_FUNCTION_VALIDATE(params.get()); 1044 EXTENSION_FUNCTION_VALIDATE(params.get());
947 DownloadItem* download_item = GetDownloadIfInProgress( 1045 DownloadItem* download_item = GetDownload(
948 profile(), include_incognito(), params->download_id); 1046 profile(), include_incognito(), params->download_id);
949 if (download_item == NULL) { 1047 if (InvalidId(download_item, &error_) ||
950 // This could be due to an invalid download ID, or it could be due to the 1048 Fault(download_item->GetState() != DownloadItem::IN_PROGRESS,
951 // download not being currently active. 1049 errors::kNotInProgress, &error_))
952 error_ = download_extension_errors::kInvalidOperationError; 1050 return false;
953 } else { 1051 // If the item is already paused, this is a no-op and the operation will
954 // If the item is already paused, this is a no-op and the 1052 // silently succeed.
955 // operation will silently succeed. 1053 download_item->Pause();
956 download_item->Pause(); 1054 RecordApiFunctions(DOWNLOADS_FUNCTION_PAUSE);
957 } 1055 return true;
958 if (error_.empty())
959 RecordApiFunctions(DOWNLOADS_FUNCTION_PAUSE);
960 return error_.empty();
961 } 1056 }
962 1057
963 DownloadsResumeFunction::DownloadsResumeFunction() {} 1058 DownloadsResumeFunction::DownloadsResumeFunction() {}
964 1059
965 DownloadsResumeFunction::~DownloadsResumeFunction() {} 1060 DownloadsResumeFunction::~DownloadsResumeFunction() {}
966 1061
967 bool DownloadsResumeFunction::RunImpl() { 1062 bool DownloadsResumeFunction::RunImpl() {
968 scoped_ptr<extensions::api::downloads::Resume::Params> params( 1063 scoped_ptr<extensions::api::downloads::Resume::Params> params(
969 extensions::api::downloads::Resume::Params::Create(*args_)); 1064 extensions::api::downloads::Resume::Params::Create(*args_));
970 EXTENSION_FUNCTION_VALIDATE(params.get()); 1065 EXTENSION_FUNCTION_VALIDATE(params.get());
971 DownloadItem* download_item = GetDownloadIfInProgress( 1066 DownloadItem* download_item = GetDownload(
972 profile(), include_incognito(), params->download_id); 1067 profile(), include_incognito(), params->download_id);
973 if (download_item == NULL) { 1068 if (InvalidId(download_item, &error_) ||
974 // This could be due to an invalid download ID, or it could be due to the 1069 Fault(download_item->IsPaused() && !download_item->CanResume(),
asanka 2013/07/26 20:28:28 !download_item->CanResume() should be sufficient.
benjhayden 2013/07/28 17:37:54 We wanted it to be not an error to call resume() f
975 // download not being currently active. 1070 errors::kNotResumable, &error_))
976 error_ = download_extension_errors::kInvalidOperationError; 1071 return false;
977 } else { 1072 // Note that if the item isn't paused, this will be a no-op, and the extension
978 // Note that if the item isn't paused, this will be a no-op, and 1073 // call will seem successful.
979 // the extension call will seem successful. 1074 download_item->Resume();
980 download_item->Resume(); 1075 RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME);
981 } 1076 return true;
982 if (error_.empty())
983 RecordApiFunctions(DOWNLOADS_FUNCTION_RESUME);
984 return error_.empty();
985 } 1077 }
986 1078
987 DownloadsCancelFunction::DownloadsCancelFunction() {} 1079 DownloadsCancelFunction::DownloadsCancelFunction() {}
988 1080
989 DownloadsCancelFunction::~DownloadsCancelFunction() {} 1081 DownloadsCancelFunction::~DownloadsCancelFunction() {}
990 1082
991 bool DownloadsCancelFunction::RunImpl() { 1083 bool DownloadsCancelFunction::RunImpl() {
992 scoped_ptr<extensions::api::downloads::Resume::Params> params( 1084 scoped_ptr<extensions::api::downloads::Resume::Params> params(
993 extensions::api::downloads::Resume::Params::Create(*args_)); 1085 extensions::api::downloads::Resume::Params::Create(*args_));
994 EXTENSION_FUNCTION_VALIDATE(params.get()); 1086 EXTENSION_FUNCTION_VALIDATE(params.get());
995 DownloadItem* download_item = GetDownloadIfInProgress( 1087 DownloadItem* download_item = GetDownload(
996 profile(), include_incognito(), params->download_id); 1088 profile(), include_incognito(), params->download_id);
997 if (download_item != NULL) 1089 if (download_item &&
1090 (download_item->GetState() == DownloadItem::IN_PROGRESS))
998 download_item->Cancel(true); 1091 download_item->Cancel(true);
999 // |download_item| can be NULL if the download ID was invalid or if the 1092 // |download_item| can be NULL if the download ID was invalid or if the
1000 // download is not currently active. Either way, it's not a failure. 1093 // download is not currently active. Either way, it's not a failure.
1001 RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL); 1094 RecordApiFunctions(DOWNLOADS_FUNCTION_CANCEL);
1002 return true; 1095 return true;
1003 } 1096 }
1004 1097
1005 DownloadsEraseFunction::DownloadsEraseFunction() {} 1098 DownloadsEraseFunction::DownloadsEraseFunction() {}
1006 1099
1007 DownloadsEraseFunction::~DownloadsEraseFunction() {} 1100 DownloadsEraseFunction::~DownloadsEraseFunction() {}
(...skipping 17 matching lines...) Expand all
1025 for (DownloadManager::DownloadVector::const_iterator it = results.begin(); 1118 for (DownloadManager::DownloadVector::const_iterator it = results.begin();
1026 it != results.end(); ++it) { 1119 it != results.end(); ++it) {
1027 json_results->Append(base::Value::CreateIntegerValue((*it)->GetId())); 1120 json_results->Append(base::Value::CreateIntegerValue((*it)->GetId()));
1028 (*it)->Remove(); 1121 (*it)->Remove();
1029 } 1122 }
1030 SetResult(json_results); 1123 SetResult(json_results);
1031 RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE); 1124 RecordApiFunctions(DOWNLOADS_FUNCTION_ERASE);
1032 return true; 1125 return true;
1033 } 1126 }
1034 1127
1128 DownloadsRemoveFileFunction::DownloadsRemoveFileFunction() {}
1129
1130 DownloadsRemoveFileFunction::~DownloadsRemoveFileFunction() {
1131 if (item_) {
1132 item_->RemoveObserver(this);
1133 item_ = NULL;
1134 }
1135 }
1136
1137 bool DownloadsRemoveFileFunction::RunImpl() {
1138 scoped_ptr<extensions::api::downloads::RemoveFile::Params> params(
1139 extensions::api::downloads::RemoveFile::Params::Create(*args_));
1140 EXTENSION_FUNCTION_VALIDATE(params.get());
1141 DownloadItem* download_item = GetDownload(
1142 profile(), include_incognito(), params->download_id);
1143 if (InvalidId(download_item, &error_) ||
1144 Fault((download_item->GetState() != DownloadItem::COMPLETE),
1145 errors::kNotComplete, &error_) ||
1146 Fault(download_item->GetFileExternallyRemoved(),
1147 errors::kFileAlreadyDeleted, &error_))
1148 return false;
1149 item_ = download_item;
1150 item_->AddObserver(this);
1151 RecordApiFunctions(DOWNLOADS_FUNCTION_DELETE_FILE);
1152 download_item->DeleteFile();
1153 return true;
1154 }
1155
1156 void DownloadsRemoveFileFunction::OnDownloadUpdated(DownloadItem* download) {
1157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1158 DCHECK_EQ(item_, download);
1159 if (!item_->GetFileExternallyRemoved())
1160 return;
1161 item_->RemoveObserver(this);
1162 item_ = NULL;
1163 SendResponse(true);
1164 }
1165
1166 void DownloadsRemoveFileFunction::OnDownloadDestroyed(DownloadItem* download) {
1167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1168 DCHECK_EQ(item_, download);
1169 item_->RemoveObserver(this);
1170 item_ = NULL;
1171 SendResponse(true);
1172 }
1173
1035 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {} 1174 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {}
1036 1175
1037 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {} 1176 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {}
1038 1177
1039 bool DownloadsAcceptDangerFunction::RunImpl() { 1178 bool DownloadsAcceptDangerFunction::RunImpl() {
1040 scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params( 1179 scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params(
1041 extensions::api::downloads::AcceptDanger::Params::Create(*args_)); 1180 extensions::api::downloads::AcceptDanger::Params::Create(*args_));
1042 EXTENSION_FUNCTION_VALIDATE(params.get()); 1181 EXTENSION_FUNCTION_VALIDATE(params.get());
1043 DownloadItem* download_item = GetDownloadIfInProgress( 1182 DownloadItem* download_item = GetDownload(
1044 profile(), include_incognito(), params->download_id); 1183 profile(), include_incognito(), params->download_id);
1045 content::WebContents* web_contents = 1184 content::WebContents* web_contents =
1046 dispatcher()->delegate()->GetVisibleWebContents(); 1185 dispatcher()->delegate()->GetVisibleWebContents();
1047 if (!download_item || 1186 if (InvalidId(download_item, &error_) ||
1048 !download_item->IsDangerous() || 1187 Fault(download_item->GetState() != DownloadItem::IN_PROGRESS,
1049 !web_contents) { 1188 errors::kNotInProgress, &error_) ||
1050 error_ = download_extension_errors::kInvalidOperationError; 1189 Fault(!download_item->IsDangerous(), errors::kNotDangerous, &error_) ||
1190 Fault(!web_contents, errors::kInvisibleContext, &error_))
1051 return false; 1191 return false;
1052 }
1053 RecordApiFunctions(DOWNLOADS_FUNCTION_ACCEPT_DANGER); 1192 RecordApiFunctions(DOWNLOADS_FUNCTION_ACCEPT_DANGER);
1054 // DownloadDangerPrompt displays a modal dialog using native widgets that the 1193 // DownloadDangerPrompt displays a modal dialog using native widgets that the
1055 // user must either accept or cancel. It cannot be scripted. 1194 // user must either accept or cancel. It cannot be scripted.
1056 DownloadDangerPrompt::Create( 1195 DownloadDangerPrompt::Create(
1057 download_item, 1196 download_item,
1058 web_contents, 1197 web_contents,
1059 true, 1198 true,
1060 base::Bind(&DownloadsAcceptDangerFunction::DangerPromptCallback, 1199 base::Bind(&DownloadsAcceptDangerFunction::DangerPromptCallback,
1061 this, true, params->download_id), 1200 this, params->download_id));
1062 base::Bind(&DownloadsAcceptDangerFunction::DangerPromptCallback,
1063 this, false, params->download_id));
1064 // DownloadDangerPrompt deletes itself 1201 // DownloadDangerPrompt deletes itself
1065 return true; 1202 return true;
1066 } 1203 }
1067 1204
1068 void DownloadsAcceptDangerFunction::DangerPromptCallback( 1205 void DownloadsAcceptDangerFunction::DangerPromptCallback(
1069 bool accept, int download_id) { 1206 int download_id, DownloadDangerPrompt::Action action) {
1070 if (accept) { 1207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1071 DownloadItem* download_item = GetDownloadIfInProgress( 1208 DownloadItem* download_item = GetDownload(
1072 profile(), include_incognito(), download_id); 1209 profile(), include_incognito(), download_id);
1073 if (download_item) 1210 if (InvalidId(download_item, &error_) ||
1211 Fault(download_item->GetState() != DownloadItem::IN_PROGRESS,
1212 errors::kNotInProgress, &error_))
1213 return;
1214 switch (action) {
1215 case DownloadDangerPrompt::ACCEPT:
1074 download_item->ValidateDangerousDownload(); 1216 download_item->ValidateDangerousDownload();
1217 break;
1218 case DownloadDangerPrompt::CANCEL:
1219 download_item->Remove();
1220 break;
1221 case DownloadDangerPrompt::DISMISS:
1222 break;
1075 } 1223 }
1076 SendResponse(error_.empty()); 1224 SendResponse(error_.empty());
1077 } 1225 }
1078 1226
1079 DownloadsShowFunction::DownloadsShowFunction() {} 1227 DownloadsShowFunction::DownloadsShowFunction() {}
1080 1228
1081 DownloadsShowFunction::~DownloadsShowFunction() {} 1229 DownloadsShowFunction::~DownloadsShowFunction() {}
1082 1230
1083 bool DownloadsShowFunction::RunImpl() { 1231 bool DownloadsShowFunction::RunImpl() {
1084 scoped_ptr<extensions::api::downloads::Show::Params> params( 1232 scoped_ptr<extensions::api::downloads::Show::Params> params(
1085 extensions::api::downloads::Show::Params::Create(*args_)); 1233 extensions::api::downloads::Show::Params::Create(*args_));
1086 EXTENSION_FUNCTION_VALIDATE(params.get()); 1234 EXTENSION_FUNCTION_VALIDATE(params.get());
1087 DownloadItem* download_item = GetDownload( 1235 DownloadItem* download_item = GetDownload(
1088 profile(), include_incognito(), params->download_id); 1236 profile(), include_incognito(), params->download_id);
1089 if (!download_item) { 1237 if (InvalidId(download_item, &error_))
1090 error_ = download_extension_errors::kInvalidOperationError;
1091 return false; 1238 return false;
1092 }
1093 download_item->ShowDownloadInShell(); 1239 download_item->ShowDownloadInShell();
1094 RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW); 1240 RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW);
1095 return true; 1241 return true;
1096 } 1242 }
1097 1243
1244 DownloadsShowDefaultFolderFunction::DownloadsShowDefaultFolderFunction() {}
1245
1246 DownloadsShowDefaultFolderFunction::~DownloadsShowDefaultFolderFunction() {}
1247
1248 bool DownloadsShowDefaultFolderFunction::RunImpl() {
1249 DownloadManager* manager = NULL;
1250 DownloadManager* incognito_manager = NULL;
1251 GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
1252 platform_util::OpenItem(DownloadPrefs::FromDownloadManager(
1253 manager)->DownloadPath());
1254 RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW_DEFAULT_FOLDER);
1255 return true;
1256 }
1257
1098 DownloadsOpenFunction::DownloadsOpenFunction() {} 1258 DownloadsOpenFunction::DownloadsOpenFunction() {}
1099 1259
1100 DownloadsOpenFunction::~DownloadsOpenFunction() {} 1260 DownloadsOpenFunction::~DownloadsOpenFunction() {}
1101 1261
1102 bool DownloadsOpenFunction::RunImpl() { 1262 bool DownloadsOpenFunction::RunImpl() {
1103 scoped_ptr<extensions::api::downloads::Open::Params> params( 1263 scoped_ptr<extensions::api::downloads::Open::Params> params(
1104 extensions::api::downloads::Open::Params::Create(*args_)); 1264 extensions::api::downloads::Open::Params::Create(*args_));
1105 EXTENSION_FUNCTION_VALIDATE(params.get()); 1265 EXTENSION_FUNCTION_VALIDATE(params.get());
1106 DownloadItem* download_item = GetDownload( 1266 DownloadItem* download_item = GetDownload(
1107 profile(), include_incognito(), params->download_id); 1267 profile(), include_incognito(), params->download_id);
1108 if (!download_item || download_item->GetState() != DownloadItem::COMPLETE || 1268 if (InvalidId(download_item, &error_) ||
1109 !GetExtension()->HasAPIPermission( 1269 Fault(download_item->GetState() != DownloadItem::COMPLETE,
1110 extensions::APIPermission::kDownloadsOpen)) { 1270 errors::kNotComplete, &error_) ||
1111 error_ = download_extension_errors::kInvalidOperationError; 1271 Fault(!GetExtension()->HasAPIPermission(
1272 extensions::APIPermission::kDownloadsOpen),
1273 errors::kOpenPermission, &error_))
1112 return false; 1274 return false;
1113 }
1114 download_item->OpenDownload(); 1275 download_item->OpenDownload();
1115 RecordApiFunctions(DOWNLOADS_FUNCTION_OPEN); 1276 RecordApiFunctions(DOWNLOADS_FUNCTION_OPEN);
1116 return true; 1277 return true;
1117 } 1278 }
1118 1279
1119 DownloadsDragFunction::DownloadsDragFunction() {} 1280 DownloadsDragFunction::DownloadsDragFunction() {}
1120 1281
1121 DownloadsDragFunction::~DownloadsDragFunction() {} 1282 DownloadsDragFunction::~DownloadsDragFunction() {}
1122 1283
1123 bool DownloadsDragFunction::RunImpl() { 1284 bool DownloadsDragFunction::RunImpl() {
1124 scoped_ptr<extensions::api::downloads::Drag::Params> params( 1285 scoped_ptr<extensions::api::downloads::Drag::Params> params(
1125 extensions::api::downloads::Drag::Params::Create(*args_)); 1286 extensions::api::downloads::Drag::Params::Create(*args_));
1126 EXTENSION_FUNCTION_VALIDATE(params.get()); 1287 EXTENSION_FUNCTION_VALIDATE(params.get());
1127 DownloadItem* download_item = GetDownload( 1288 DownloadItem* download_item = GetDownload(
1128 profile(), include_incognito(), params->download_id); 1289 profile(), include_incognito(), params->download_id);
1129 content::WebContents* web_contents = 1290 content::WebContents* web_contents =
1130 dispatcher()->delegate()->GetVisibleWebContents(); 1291 dispatcher()->delegate()->GetVisibleWebContents();
1131 if (!download_item || !web_contents) { 1292 if (InvalidId(download_item, &error_) ||
1132 error_ = download_extension_errors::kInvalidOperationError; 1293 Fault(!web_contents, errors::kInvisibleContext, &error_))
1133 return false; 1294 return false;
1134 }
1135 RecordApiFunctions(DOWNLOADS_FUNCTION_DRAG); 1295 RecordApiFunctions(DOWNLOADS_FUNCTION_DRAG);
1136 gfx::Image* icon = g_browser_process->icon_manager()->LookupIconFromFilepath( 1296 gfx::Image* icon = g_browser_process->icon_manager()->LookupIconFromFilepath(
1137 download_item->GetTargetFilePath(), IconLoader::NORMAL); 1297 download_item->GetTargetFilePath(), IconLoader::NORMAL);
1138 gfx::NativeView view = web_contents->GetView()->GetNativeView(); 1298 gfx::NativeView view = web_contents->GetView()->GetNativeView();
1139 { 1299 {
1140 // Enable nested tasks during DnD, while |DragDownload()| blocks. 1300 // Enable nested tasks during DnD, while |DragDownload()| blocks.
1141 base::MessageLoop::ScopedNestableTaskAllower allow( 1301 base::MessageLoop::ScopedNestableTaskAllower allow(
1142 base::MessageLoop::current()); 1302 base::MessageLoop::current());
1143 download_util::DragDownload(download_item, icon, view); 1303 download_util::DragDownload(download_item, icon, view);
1144 } 1304 }
(...skipping 16 matching lines...) Expand all
1161 scoped_ptr<extensions::api::downloads::GetFileIcon::Params> params( 1321 scoped_ptr<extensions::api::downloads::GetFileIcon::Params> params(
1162 extensions::api::downloads::GetFileIcon::Params::Create(*args_)); 1322 extensions::api::downloads::GetFileIcon::Params::Create(*args_));
1163 EXTENSION_FUNCTION_VALIDATE(params.get()); 1323 EXTENSION_FUNCTION_VALIDATE(params.get());
1164 const extensions::api::downloads::GetFileIconOptions* options = 1324 const extensions::api::downloads::GetFileIconOptions* options =
1165 params->options.get(); 1325 params->options.get();
1166 int icon_size = kDefaultIconSize; 1326 int icon_size = kDefaultIconSize;
1167 if (options && options->size.get()) 1327 if (options && options->size.get())
1168 icon_size = *options->size.get(); 1328 icon_size = *options->size.get();
1169 DownloadItem* download_item = GetDownload( 1329 DownloadItem* download_item = GetDownload(
1170 profile(), include_incognito(), params->download_id); 1330 profile(), include_incognito(), params->download_id);
1171 if (!download_item || download_item->GetTargetFilePath().empty()) { 1331 if (InvalidId(download_item, &error_) ||
1172 error_ = download_extension_errors::kInvalidOperationError; 1332 Fault(download_item->GetTargetFilePath().empty(),
1333 errors::kEmptyFile, &error_))
1173 return false; 1334 return false;
1174 }
1175 // In-progress downloads return the intermediate filename for GetFullPath() 1335 // In-progress downloads return the intermediate filename for GetFullPath()
1176 // which doesn't have the final extension. Therefore a good file icon can't be 1336 // which doesn't have the final extension. Therefore a good file icon can't be
1177 // found, so use GetTargetFilePath() instead. 1337 // found, so use GetTargetFilePath() instead.
1178 DCHECK(icon_extractor_.get()); 1338 DCHECK(icon_extractor_.get());
1179 DCHECK(icon_size == 16 || icon_size == 32); 1339 DCHECK(icon_size == 16 || icon_size == 32);
1180 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath( 1340 EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath(
1181 download_item->GetTargetFilePath(), 1341 download_item->GetTargetFilePath(),
1182 IconLoaderSizeFromPixelSize(icon_size), 1342 IconLoaderSizeFromPixelSize(icon_size),
1183 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this))); 1343 base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this)));
1184 return true; 1344 return true;
1185 } 1345 }
1186 1346
1187 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) { 1347 void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) {
1188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1189 if (url.empty()) { 1349 if (Fault(url.empty(), errors::kIconNotFound, &error_)) {
1190 error_ = download_extension_errors::kIconNotFoundError; 1350 SendResponse(false);
1191 } else { 1351 return;
1192 RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON);
1193 SetResult(base::Value::CreateStringValue(url));
1194 } 1352 }
1195 SendResponse(error_.empty()); 1353 RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON);
1354 SetResult(base::Value::CreateStringValue(url));
1355 SendResponse(true);
1196 } 1356 }
1197 1357
1198 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( 1358 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(
1199 Profile* profile, 1359 Profile* profile,
1200 DownloadManager* manager) 1360 DownloadManager* manager)
1201 : profile_(profile), 1361 : profile_(profile),
1202 notifier_(manager, this) { 1362 notifier_(manager, this) {
1203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1204 DCHECK(profile_); 1364 DCHECK(profile_);
1205 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> 1365 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1260 item, profile_->IsOffTheRecord()).release(); 1420 item, profile_->IsOffTheRecord()).release();
1261 json->SetString(kFilenameKey, suggested_path.LossyDisplayName()); 1421 json->SetString(kFilenameKey, suggested_path.LossyDisplayName());
1262 DispatchEvent(events::kOnDownloadDeterminingFilename, 1422 DispatchEvent(events::kOnDownloadDeterminingFilename,
1263 false, 1423 false,
1264 base::Bind(&OnDeterminingFilenameWillDispatchCallback, 1424 base::Bind(&OnDeterminingFilenameWillDispatchCallback,
1265 &any_determiners, 1425 &any_determiners,
1266 data), 1426 data),
1267 json); 1427 json);
1268 if (!any_determiners) { 1428 if (!any_determiners) {
1269 data->ClearPendingDeterminers(); 1429 data->ClearPendingDeterminers();
1270 no_change.Run(); 1430 if (!data->creator_suggested_filename().empty()) {
1431 change.Run(data->creator_suggested_filename(),
1432 ConvertConflictAction(data->creator_conflict_action()));
1433 // If all listeners are removed, don't keep |data| around.
1434 data->ResetCreatorSuggestion();
1435 } else {
1436 no_change.Run();
1437 }
1271 } 1438 }
1272 } 1439 }
1273 1440
1274 bool ExtensionDownloadsEventRouter::DetermineFilename( 1441 bool ExtensionDownloadsEventRouter::DetermineFilename(
1275 Profile* profile, 1442 Profile* profile,
1276 bool include_incognito, 1443 bool include_incognito,
1277 const std::string& ext_id, 1444 const std::string& ext_id,
1278 int download_id, 1445 int download_id,
1279 const base::FilePath& const_filename, 1446 const base::FilePath& const_filename,
1280 extensions::api::downloads::FilenameConflictAction conflict_action, 1447 extensions::api::downloads::FilenameConflictAction conflict_action,
1281 std::string* error) { 1448 std::string* error) {
1282 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1449 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1283 DownloadItem* item = GetDownload(profile, include_incognito, download_id); 1450 DownloadItem* item = GetDownload(profile, include_incognito, download_id);
1284 if (!item) {
1285 *error = download_extension_errors::kInvalidOperationError;
1286 return false;
1287 }
1288 ExtensionDownloadsEventRouterData* data = 1451 ExtensionDownloadsEventRouterData* data =
1289 ExtensionDownloadsEventRouterData::Get(item); 1452 item ? ExtensionDownloadsEventRouterData::Get(item) : NULL;
1290 if (!data) {
1291 *error = download_extension_errors::kInvalidOperationError;
1292 return false;
1293 }
1294 // maxListeners=1 in downloads.idl and suggestCallback in 1453 // maxListeners=1 in downloads.idl and suggestCallback in
1295 // downloads_custom_bindings.js should prevent duplicate DeterminerCallback 1454 // downloads_custom_bindings.js should prevent duplicate DeterminerCallback
1296 // calls from the same renderer, but an extension may have more than one 1455 // calls from the same renderer, but an extension may have more than one
1297 // renderer, so don't DCHECK(!reported). 1456 // renderer, so don't DCHECK(!reported).
1298 if (data->DeterminerAlreadyReported(ext_id)) { 1457 if (InvalidId(item, error) ||
1299 *error = download_extension_errors::kTooManyListenersError; 1458 Fault(item->GetState() != DownloadItem::IN_PROGRESS,
1459 errors::kNotInProgress, error) ||
1460 Fault(!data, errors::kUnexpectedDeterminer, error) ||
1461 Fault(data->DeterminerAlreadyReported(ext_id),
1462 errors::kTooManyListeners, error))
1300 return false; 1463 return false;
1301 }
1302 if (item->GetState() != DownloadItem::IN_PROGRESS) {
1303 *error = download_extension_errors::kInvalidOperationError;
1304 return false;
1305 }
1306 base::FilePath::StringType filename_str(const_filename.value()); 1464 base::FilePath::StringType filename_str(const_filename.value());
1307 // Allow windows-style directory separators on all platforms. 1465 // Allow windows-style directory separators on all platforms.
1308 std::replace(filename_str.begin(), filename_str.end(), 1466 std::replace(filename_str.begin(), filename_str.end(),
1309 FILE_PATH_LITERAL('\\'), FILE_PATH_LITERAL('/')); 1467 FILE_PATH_LITERAL('\\'), FILE_PATH_LITERAL('/'));
1310 base::FilePath filename(filename_str); 1468 base::FilePath filename(filename_str);
1311 bool valid_filename = net::IsSafePortableRelativePath(filename); 1469 bool valid_filename = net::IsSafePortableRelativePath(filename);
1312 filename = (valid_filename ? filename.NormalizePathSeparators() : 1470 filename = (valid_filename ? filename.NormalizePathSeparators() :
1313 base::FilePath()); 1471 base::FilePath());
1314 if (!data->DeterminerCallback(ext_id, filename, conflict_action)) { 1472 // If the invalid filename check is moved to before DeterminerCallback(), then
1315 // Nobody expects this ext_id! 1473 // it will block forever waiting for this ext_id to report.
1316 *error = download_extension_errors::kInvalidOperationError; 1474 if (Fault(!data->DeterminerCallback(ext_id, filename, conflict_action),
1475 errors::kUnexpectedDeterminer, error) ||
1476 Fault((!const_filename.empty() && !valid_filename),
1477 errors::kInvalidFilename, error))
1317 return false; 1478 return false;
1318 }
1319 if (!const_filename.empty() && !valid_filename) {
1320 // If this is moved to before DeterminerCallback(), then it will block
1321 // forever waiting for this ext_id to report.
1322 *error = download_extension_errors::kInvalidFilenameError;
1323 return false;
1324 }
1325 return true; 1479 return true;
1326 } 1480 }
1327 1481
1328 void ExtensionDownloadsEventRouter::OnListenerRemoved( 1482 void ExtensionDownloadsEventRouter::OnListenerRemoved(
1329 const extensions::EventListenerInfo& details) { 1483 const extensions::EventListenerInfo& details) {
1330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1484 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1331 DownloadManager* manager = notifier_.GetManager(); 1485 DownloadManager* manager = notifier_.GetManager();
1332 if (!manager) 1486 if (!manager)
1333 return; 1487 return;
1334 bool determiner_removed = ( 1488 bool determiner_removed = (
(...skipping 15 matching lines...) Expand all
1350 if (!data) 1504 if (!data)
1351 continue; 1505 continue;
1352 if (determiner_removed) { 1506 if (determiner_removed) {
1353 // Notify any items that may be waiting for callbacks from this 1507 // Notify any items that may be waiting for callbacks from this
1354 // extension/determiner. This will almost always be a no-op, however, it 1508 // extension/determiner. This will almost always be a no-op, however, it
1355 // is possible for an extension renderer to be unloaded while a download 1509 // is possible for an extension renderer to be unloaded while a download
1356 // item is waiting for a determiner. In that case, the download item 1510 // item is waiting for a determiner. In that case, the download item
1357 // should proceed. 1511 // should proceed.
1358 data->DeterminerRemoved(details.extension_id); 1512 data->DeterminerRemoved(details.extension_id);
1359 } 1513 }
1360 if (!any_listeners) { 1514 if (!any_listeners &&
1515 data->creator_suggested_filename().empty()) {
1361 ExtensionDownloadsEventRouterData::Remove(*iter); 1516 ExtensionDownloadsEventRouterData::Remove(*iter);
1362 } 1517 }
1363 } 1518 }
1364 } 1519 }
1365 1520
1366 // That's all the methods that have to do with filename determination. The rest 1521 // That's all the methods that have to do with filename determination. The rest
1367 // have to do with the other, less special events. 1522 // have to do with the other, less special events.
1368 1523
1369 void ExtensionDownloadsEventRouter::OnDownloadCreated( 1524 void ExtensionDownloadsEventRouter::OnDownloadCreated(
1370 DownloadManager* manager, DownloadItem* download_item) { 1525 DownloadManager* manager, DownloadItem* download_item) {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1420 std::set<std::string> new_fields; 1575 std::set<std::string> new_fields;
1421 bool changed = false; 1576 bool changed = false;
1422 1577
1423 // For each field in the new json representation of the download_item except 1578 // For each field in the new json representation of the download_item except
1424 // the bytesReceived field, if the field has changed from the previous old 1579 // the bytesReceived field, if the field has changed from the previous old
1425 // json, set the differences in the |delta| object and remember that something 1580 // json, set the differences in the |delta| object and remember that something
1426 // significant changed. 1581 // significant changed.
1427 for (base::DictionaryValue::Iterator iter(*new_json.get()); 1582 for (base::DictionaryValue::Iterator iter(*new_json.get());
1428 !iter.IsAtEnd(); iter.Advance()) { 1583 !iter.IsAtEnd(); iter.Advance()) {
1429 new_fields.insert(iter.key()); 1584 new_fields.insert(iter.key());
1430 if (iter.key() != kBytesReceivedKey) { 1585 if (IsDownloadDeltaField(iter.key())) {
1431 const base::Value* old_value = NULL; 1586 const base::Value* old_value = NULL;
1432 if (!data->json().HasKey(iter.key()) || 1587 if (!data->json().HasKey(iter.key()) ||
1433 (data->json().Get(iter.key(), &old_value) && 1588 (data->json().Get(iter.key(), &old_value) &&
1434 !iter.value().Equals(old_value))) { 1589 !iter.value().Equals(old_value))) {
1435 delta->Set(iter.key() + ".current", iter.value().DeepCopy()); 1590 delta->Set(iter.key() + ".current", iter.value().DeepCopy());
1436 if (old_value) 1591 if (old_value)
1437 delta->Set(iter.key() + ".previous", old_value->DeepCopy()); 1592 delta->Set(iter.key() + ".previous", old_value->DeepCopy());
1438 changed = true; 1593 changed = true;
1439 } 1594 }
1440 } 1595 }
1441 } 1596 }
1442 1597
1443 // If a field was in the previous json but is not in the new json, set the 1598 // If a field was in the previous json but is not in the new json, set the
1444 // difference in |delta|. 1599 // difference in |delta|.
1445 for (base::DictionaryValue::Iterator iter(data->json()); 1600 for (base::DictionaryValue::Iterator iter(data->json());
1446 !iter.IsAtEnd(); iter.Advance()) { 1601 !iter.IsAtEnd(); iter.Advance()) {
1447 if (new_fields.find(iter.key()) == new_fields.end()) { 1602 if ((new_fields.find(iter.key()) == new_fields.end()) &&
1603 IsDownloadDeltaField(iter.key())) {
1604 // estimatedEndTime disappears after completion, but bytesReceived stays.
1448 delta->Set(iter.key() + ".previous", iter.value().DeepCopy()); 1605 delta->Set(iter.key() + ".previous", iter.value().DeepCopy());
1449 changed = true; 1606 changed = true;
1450 } 1607 }
1451 } 1608 }
1452 1609
1453 // Update the OnChangedStat and dispatch the event if something significant 1610 // Update the OnChangedStat and dispatch the event if something significant
1454 // changed. Replace the stored json with the new json. 1611 // changed. Replace the stored json with the new json.
1455 data->OnItemUpdated(); 1612 data->OnItemUpdated();
1456 if (changed) { 1613 if (changed) {
1457 DispatchEvent(events::kOnDownloadChanged, 1614 DispatchEvent(events::kOnDownloadChanged,
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1501 DownloadsNotificationSource notification_source; 1658 DownloadsNotificationSource notification_source;
1502 notification_source.event_name = event_name; 1659 notification_source.event_name = event_name;
1503 notification_source.profile = profile_; 1660 notification_source.profile = profile_;
1504 content::Source<DownloadsNotificationSource> content_source( 1661 content::Source<DownloadsNotificationSource> content_source(
1505 &notification_source); 1662 &notification_source);
1506 content::NotificationService::current()->Notify( 1663 content::NotificationService::current()->Notify(
1507 chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT, 1664 chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT,
1508 content_source, 1665 content_source,
1509 content::Details<std::string>(&json_args)); 1666 content::Details<std::string>(&json_args));
1510 } 1667 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698