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

Powered by Google App Engine
This is Rietveld 408576698