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

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

Powered by Google App Engine
This is Rietveld 408576698