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

Side by Side Diff: chrome/browser/download/download_target_determiner.cc

Issue 12850002: Move download filename determintion into a separate class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Get rid of download_file_picker_chromeos Created 7 years, 8 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
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/download/download_target_determiner.h"
6
7 #include "base/prefs/pref_service.h"
8 #include "base/rand_util.h"
9 #include "base/stringprintf.h"
10 #include "base/time.h"
11 #include "chrome/browser/download/chrome_download_manager_delegate.h"
12 #include "chrome/browser/download/download_crx_util.h"
13 #include "chrome/browser/download/download_extensions.h"
14 #include "chrome/browser/download/download_prefs.h"
15 #include "chrome/browser/download/download_util.h"
16 #include "chrome/browser/extensions/webstore_installer.h"
17 #include "chrome/browser/history/history_service.h"
18 #include "chrome/browser/history/history_service_factory.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/common/extensions/extension.h"
21 #include "chrome/common/extensions/feature_switch.h"
22 #include "chrome/common/pref_names.h"
23 #include "content/public/browser/browser_context.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "grit/generated_resources.h"
26 #include "net/base/net_util.h"
27 #include "ui/base/l10n/l10n_util.h"
28
29 #if defined(OS_CHROMEOS)
30 #include "chrome/browser/chromeos/drive/drive_download_handler.h"
31 #include "chrome/browser/chromeos/drive/drive_file_system_util.h"
32 #endif
33
34 using content::BrowserThread;
35 using content::DownloadItem;
36
37 namespace {
38
39 // Condenses the results from HistoryService::GetVisibleVisitCountToHost() to a
40 // single bool. A host is considered visited before if prior visible vists were
benjhayden 2013/04/26 15:07:37 s/vists/visits/
asanka 2013/04/26 17:02:21 Done.
41 // found in history and the first such visit was earlier than the most recent
42 // midnight.
43 void VisitCountsToVisitedBefore(
44 const base::Callback<void(bool)>& callback,
45 HistoryService::Handle unused_handle,
46 bool found_visits,
47 int count,
48 base::Time first_visit) {
49 callback.Run(
50 found_visits && count > 0 &&
51 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight()));
52 }
53
54 } // namespace
55
56 DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() {
57 }
58
59 DownloadTargetDeterminer::DownloadTargetDeterminer(
60 DownloadItem* download,
61 DownloadPrefs* download_prefs,
62 const base::FilePath& last_selected_directory,
63 DownloadTargetDeterminerDelegate* delegate,
64 const content::DownloadTargetCallback& callback)
65 : next_state_(STATE_GENERATE_TARGET_PATH),
66 should_prompt_(false),
67 conflict_action_(download->GetForcedFilePath().empty() ?
68 DownloadPathReservationTracker::UNIQUIFY :
69 DownloadPathReservationTracker::OVERWRITE),
70 danger_type_(download->GetDangerType()),
71 download_(download),
72 download_prefs_(download_prefs),
73 delegate_(delegate),
74 last_selected_directory_(last_selected_directory),
75 completion_callback_(callback),
76 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
78 DCHECK(download_);
79 DCHECK(delegate);
80 download_->AddObserver(this);
81
82 DoLoop();
83 }
84
85 DownloadTargetDeterminer::~DownloadTargetDeterminer() {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
87 DCHECK(download_);
88 DCHECK(completion_callback_.is_null());
89 download_->RemoveObserver(this);
90 }
91
92 void DownloadTargetDeterminer::DoLoop() {
93 Result result = CONTINUE;
94 do {
95 State current_state = next_state_;
96 next_state_ = STATE_NONE;
97
98 switch (current_state) {
99 case STATE_GENERATE_TARGET_PATH:
100 result = DoGenerateTargetPath();
101 break;
102 case STATE_NOTIFY_EXTENSIONS:
103 result = DoNotifyExtensions();
104 break;
105 case STATE_RESERVE_VIRTUAL_PATH:
106 result = DoReserveVirtualPath();
107 break;
108 case STATE_PROMPT_USER_FOR_DOWNLOAD_PATH:
109 result = DoPromptUserForDownloadPath();
110 break;
111 case STATE_DETERMINE_LOCAL_PATH:
112 result = DoDetermineLocalPath();
113 break;
114 case STATE_CHECK_DOWNLOAD_URL:
115 result = DoCheckDownloadUrl();
116 break;
117 case STATE_DETERMINE_INTERMEDIATE_PATH:
118 result = DoDetermineIntermediatePath();
119 break;
120 case STATE_CHECK_VISITED_REFERRER_BEFORE:
121 result = DoCheckVisitedReferrerBefore();
122 break;
123 case STATE_NONE:
124 NOTREACHED();
125 return;
126 }
127 } while (result == CONTINUE);
128 // Note that if a callback completes synchronously, the handler will still
129 // return QUIT_DOLOOP. In this case, an inner DoLoop() may complete the target
130 // determination and delete |this|.
131
132 if (result == COMPLETE)
133 ScheduleCallbackAndDeleteSelf();
134 }
135
136 DownloadTargetDeterminer::Result
137 DownloadTargetDeterminer::DoGenerateTargetPath() {
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
139 DCHECK(virtual_path_.empty());
140 DCHECK(local_path_.empty());
141 bool is_forced_path = !download_->GetForcedFilePath().empty();
142
143 next_state_ = STATE_NOTIFY_EXTENSIONS;
144
145 // If we don't have a forced path, we should construct a path for the
146 // download. Forced paths are only specified for programmatic downloads
147 // (WebStore, Drag&Drop). Treat the path as a virtual path. We will eventually
148 // determine whether this is a local path and if not, figure out a local path.
149 if (!is_forced_path) {
150 std::string default_filename(
151 l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME));
152 base::FilePath generated_filename = net::GenerateFileName(
153 download_->GetURL(),
154 download_->GetContentDisposition(),
155 GetProfile()->GetPrefs()->GetString(prefs::kDefaultCharset),
156 download_->GetSuggestedFilename(),
157 download_->GetMimeType(),
158 default_filename);
159 should_prompt_ = ShouldPromptForDownload(generated_filename);
160 base::FilePath target_directory;
161 if (should_prompt_ && !last_selected_directory_.empty()) {
162 DCHECK(!download_prefs_->IsDownloadPathManaged());
163 // If the user is going to be prompted and the user has been prompted
164 // before, then always prefer the last directory that the user selected.
165 target_directory = last_selected_directory_;
166 } else {
167 target_directory = download_prefs_->DownloadPath();
168 }
169 virtual_path_ = target_directory.Append(generated_filename);
170 } else {
171 DCHECK(!should_prompt_);
172 virtual_path_ = download_->GetForcedFilePath();
173 }
174 DCHECK(virtual_path_.IsAbsolute());
175 DVLOG(20) << "Generated virtual path: " << virtual_path_.AsUTF8Unsafe();
176
177 // If the download is DOA, don't bother going any further. This would be the
178 // case for a download that failed to initialize (e.g. the initial temporary
179 // file couldn't be created because both the downloads directory and the
180 // temporary directory are unwriteable).
181 if (!download_->IsInProgress())
benjhayden 2013/04/26 15:07:37 Why not do this before computing virtual_path_?
asanka 2013/04/26 17:02:21 The point is to be able to compute a suggested pat
benjhayden 2013/04/26 17:25:56 Can you comment that this check happens after comp
asanka 2013/04/29 18:43:19 Done.
182 return COMPLETE;
183 return CONTINUE;
184 }
185
186 DownloadTargetDeterminer::Result
187 DownloadTargetDeterminer::DoNotifyExtensions() {
188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
189 DCHECK(!virtual_path_.empty());
190
191 next_state_ = STATE_RESERVE_VIRTUAL_PATH;
192
193 // If the target path is forced or if we don't have an extensions event
194 // router, then proceed with the original path.
195 if (!download_->GetForcedFilePath().empty())
196 return CONTINUE;
197
198 delegate_->NotifyExtensions(download_, virtual_path_,
199 base::Bind(&DownloadTargetDeterminer::NotifyExtensionsDone,
200 weak_ptr_factory_.GetWeakPtr()));
201 return QUIT_DOLOOP;
202 }
203
204 void DownloadTargetDeterminer::NotifyExtensionsDone(
205 const base::FilePath& suggested_path,
206 DownloadPathReservationTracker::FilenameConflictAction conflict_action) {
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
208 DVLOG(20) << "Extension suggested path: " << suggested_path.AsUTF8Unsafe();
209
210 if (!suggested_path.empty()) {
211 // TODO(asanka, benjhayden): The suggested path may contain path fragments.
benjhayden 2013/04/26 15:07:37 Remove this TODO since I have a pending CL to hand
asanka 2013/04/26 17:02:21 Done.
212 // We need to validate each component individually. http://crbug.com/181332.
213
214 // If an extension overrides the filename, then the target directory will be
215 // forced to download_prefs_->DownloadPath() since extensions cannot place
216 // downloaded files anywhere except there. This prevents subdirectories from
217 // accumulating: if an extension is allowed to say that a file should go in
218 // last_download_path/music/foo.mp3, then last_download_path will accumulate
219 // the subdirectory /music/ so that the next download may end up in
220 // Downloads/music/music/music/bar.mp3.
221 base::FilePath new_path(download_prefs_->DownloadPath().Append(
222 suggested_path).NormalizePathSeparators());
223 // Do not pass a mime type to GenerateSafeFileName so that it does not force
224 // the filename to have an extension if the (Chrome) extension does not
225 // suggest it.
226 net::GenerateSafeFileName(std::string(), false, &new_path);
227 virtual_path_ = new_path;
228 conflict_action_ = conflict_action;
229 }
230
231 DoLoop();
232 }
233
234 DownloadTargetDeterminer::Result
235 DownloadTargetDeterminer::DoReserveVirtualPath() {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237 DCHECK(!virtual_path_.empty());
238
239 next_state_ = STATE_PROMPT_USER_FOR_DOWNLOAD_PATH;
240
241 delegate_->ReserveVirtualPath(
242 download_, virtual_path_, conflict_action_,
243 base::Bind(&DownloadTargetDeterminer::ReserveVirtualPathDone,
244 weak_ptr_factory_.GetWeakPtr()));
245 return QUIT_DOLOOP;
246 }
247
248 void DownloadTargetDeterminer::ReserveVirtualPathDone(
249 const base::FilePath& path, bool verified) {
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
251 DVLOG(20) << "Reserved path: " << path.AsUTF8Unsafe()
252 << " Verified:" << verified;
253 should_prompt_ = (should_prompt_ || !verified);
254 if (verified)
255 virtual_path_ = path;
256 DoLoop();
257 }
258
259 DownloadTargetDeterminer::Result
260 DownloadTargetDeterminer::DoPromptUserForDownloadPath() {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
262 DCHECK(!virtual_path_.empty());
263
264 next_state_ = STATE_DETERMINE_LOCAL_PATH;
265
266 if (should_prompt_) {
benjhayden 2013/04/26 15:07:37 Why doesn't ReserveVirtualPathDone() skip past STA
asanka 2013/04/26 17:02:21 This is roughly following the pattern elsewhere th
267 delegate_->PromptUserForDownloadPath(
268 download_,
269 virtual_path_,
270 base::Bind(&DownloadTargetDeterminer::PromptUserForDownloadPathDone,
271 weak_ptr_factory_.GetWeakPtr()));
272 return QUIT_DOLOOP;
273 }
274 return CONTINUE;
275 }
276
277 void DownloadTargetDeterminer::PromptUserForDownloadPathDone(
278 const base::FilePath& virtual_path) {
279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
280 DVLOG(20) << "User selected path:" << virtual_path.AsUTF8Unsafe();
281 if (virtual_path.empty()) {
282 CancelOnFailureAndDeleteSelf();
283 return;
284 }
285 virtual_path_ = virtual_path;
286 DoLoop();
287 }
288
289 DownloadTargetDeterminer::Result
290 DownloadTargetDeterminer::DoDetermineLocalPath() {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
292 DCHECK(!virtual_path_.empty());
293 DCHECK(local_path_.empty());
294
295 next_state_ = STATE_CHECK_DOWNLOAD_URL;
296
297 delegate_->DetermineLocalPath(
298 download_,
299 virtual_path_,
300 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone,
301 weak_ptr_factory_.GetWeakPtr()));
302 return QUIT_DOLOOP;
303 }
304
305 void DownloadTargetDeterminer::DetermineLocalPathDone(
306 const base::FilePath& local_path) {
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
308 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe();
309 local_path_ = local_path;
benjhayden 2013/04/26 15:07:37 Why set virtual_path_ *after* maybe calling Cancel
asanka 2013/04/26 17:02:21 Done.
310 if (local_path_.empty()) {
311 // Path subsitution failed.
312 CancelOnFailureAndDeleteSelf();
313 return;
314 }
315 DoLoop();
316 }
317
318 DownloadTargetDeterminer::Result
319 DownloadTargetDeterminer::DoCheckDownloadUrl() {
320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
321 DCHECK(!virtual_path_.empty());
322 next_state_ = STATE_CHECK_VISITED_REFERRER_BEFORE;
323 delegate_->CheckDownloadUrl(
324 download_,
325 virtual_path_,
326 base::Bind(&DownloadTargetDeterminer::CheckDownloadUrlDone,
327 weak_ptr_factory_.GetWeakPtr()));
328 return QUIT_DOLOOP;
329 }
330
331 void DownloadTargetDeterminer::CheckDownloadUrlDone(
332 content::DownloadDangerType danger_type) {
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
334 DVLOG(20) << "URL Check Result:" << danger_type;
335 danger_type_ = danger_type;
336 DoLoop();
337 }
338
339 DownloadTargetDeterminer::Result
340 DownloadTargetDeterminer::DoCheckVisitedReferrerBefore() {
341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
342
343 next_state_ = STATE_DETERMINE_INTERMEDIATE_PATH;
344
345 // Checking if there are prior visits to the referrer is only necessary if the
346 // danger level of the download depends on the file type. This excludes cases
347 // where the download has already been deemed dangerous, or where the user is
348 // going to be prompted or where this is a programmatic download.
349 if (danger_type_ != content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
benjhayden 2013/04/26 15:07:37 Again, why not move this into CheckDownloadUrlDone
asanka 2013/04/26 17:02:21 As above.
350 should_prompt_ ||
351 !download_->GetForcedFilePath().empty()) {
352 return CONTINUE;
353 }
354
355 // Only ping the history DB if the download would be considered safe if there
356 // are prior visits and is considered dangerous otherwise.
357 if (!IsDangerousFile(VISITED_REFERRER) &&
358 IsDangerousFile(NO_VISITS_TO_REFERRER)) {
359 // HistoryServiceFactory redirects incognito profiles to on-record profiles.
360 // There's no history for on-record profiles in unit_tests.
361 HistoryService* history_service = HistoryServiceFactory::GetForProfile(
362 GetProfile(), Profile::EXPLICIT_ACCESS);
363
364 if (history_service && download_->GetReferrerUrl().is_valid()) {
365 history_service->GetVisibleVisitCountToHost(
benjhayden 2013/04/25 17:16:04 Would moving this out to the delegate be worth the
asanka 2013/04/25 19:08:26 The history service is currently testable. See the
benjhayden 2013/04/26 15:07:37 nm, this looks good.
366 download_->GetReferrerUrl(), &history_consumer_,
367 base::Bind(&VisitCountsToVisitedBefore, base::Bind(
368 &DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone,
369 weak_ptr_factory_.GetWeakPtr())));
370 return QUIT_DOLOOP;
371 }
372 }
373
374 // If the danger level doesn't depend on having visited the refererrer URL or
375 // if original profile doesn't have a HistoryService or the referrer url is
376 // invalid, then assume the referrer has not been visited before.
377 if (IsDangerousFile(NO_VISITS_TO_REFERRER))
benjhayden 2013/04/26 15:07:37 Can you merge this with the previous if-block so t
asanka 2013/04/26 17:02:21 Done.
378 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE;
379 return CONTINUE;
380 }
381
382 void DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone(
383 bool visited_referrer_before) {
384 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
385 if (IsDangerousFile(
386 visited_referrer_before ? VISITED_REFERRER : NO_VISITS_TO_REFERRER))
387 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE;
388 DoLoop();
389 }
390
391 DownloadTargetDeterminer::Result
392 DownloadTargetDeterminer::DoDetermineIntermediatePath() {
benjhayden 2013/04/26 15:07:37 Should this line be indented like the others like
asanka 2013/04/26 17:02:21 Done.
393 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
394 DCHECK(!virtual_path_.empty());
395 DCHECK(!local_path_.empty());
396 DCHECK(intermediate_path_.empty());
397
398 next_state_ = STATE_NONE;
399
400 if (virtual_path_.BaseName() != local_path_.BaseName() ||
401 (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS &&
402 !download_->GetForcedFilePath().empty())) {
403 // If the actual target of the download is a virtual path, then the local
404 // path is considered to point to a temporary path. A separate intermediate
405 // path is unnecessary since the local path already serves that purpose.
406 //
407 // Also, if the download has a forced path and is safe, then just use the
408 // target path.
409 intermediate_path_ = local_path_;
410 } else if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
411 // If the download is not dangerous, just append .crdownload to the target
412 // path.
413 intermediate_path_ = download_util::GetCrDownloadPath(local_path_);
414 } else {
415 // If the download is potentially dangerous we create a filename of the form
416 // 'Unconfirmed <random>.crdownload'.
417 base::FilePath::StringType file_name;
418 base::FilePath dir = local_path_.DirName();
419 #if defined(OS_WIN)
420 string16 unconfirmed_prefix =
421 l10n_util::GetStringUTF16(IDS_DOWNLOAD_UNCONFIRMED_PREFIX);
422 #else
423 std::string unconfirmed_prefix =
424 l10n_util::GetStringUTF8(IDS_DOWNLOAD_UNCONFIRMED_PREFIX);
425 #endif
426 base::SStringPrintf(
427 &file_name,
428 unconfirmed_prefix.append(
429 FILE_PATH_LITERAL(" %d.crdownload")).c_str(),
benjhayden 2013/04/26 15:07:37 Should that string be a kConstant?
asanka 2013/04/26 17:02:21 Done. I was just moving code around, but personall
430 base::RandInt(0, 1000000));
benjhayden 2013/04/26 15:07:37 kConstant = 1000000?
asanka 2013/04/26 17:02:21 Done.
431 intermediate_path_ = dir.Append(file_name);
432 }
433
434 return COMPLETE;
435 }
436
437 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() {
438 DCHECK(download_);
439 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe()
440 << " Local:" << local_path_.AsUTF8Unsafe()
441 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe()
442 << " Should prompt:" << should_prompt_
443 << " Danger type:" << danger_type_;
444 MessageLoop::current()->PostTask(
445 FROM_HERE,
446 base::Bind(completion_callback_,
447 local_path_,
448 (should_prompt_ ? DownloadItem::TARGET_DISPOSITION_PROMPT :
449 DownloadItem::TARGET_DISPOSITION_OVERWRITE),
450 danger_type_,
451 intermediate_path_));
452 completion_callback_.Reset();
453 delete this;
454 }
455
456 void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() {
457 // Path substitution failed.
458 virtual_path_.clear();
459 local_path_.clear();
460 intermediate_path_.clear();
461 ScheduleCallbackAndDeleteSelf();
462 }
463
464 Profile* DownloadTargetDeterminer::GetProfile() {
465 DCHECK(download_->GetBrowserContext());
466 return Profile::FromBrowserContext(download_->GetBrowserContext());
467 }
468
469 bool DownloadTargetDeterminer::ShouldPromptForDownload(
470 const base::FilePath& filename) {
471 // If the download path is forced, don't prompt.
472 if (!download_->GetForcedFilePath().empty()) {
473 // 'Save As' downloads shouldn't have a forced path.
474 DCHECK_NE(DownloadItem::TARGET_DISPOSITION_PROMPT,
475 download_->GetTargetDisposition());
476 return false;
477 }
478
479 // Don't ask where to save if the download path is managed. Even if the user
480 // wanted to be prompted for "all" downloads, or if this was a 'Save As'
481 // download.
482 if (download_prefs_->IsDownloadPathManaged())
483 return false;
484
485 // Prompt if this is a 'Save As' download.
486 if (download_->GetTargetDisposition() ==
487 DownloadItem::TARGET_DISPOSITION_PROMPT)
488 return true;
489
490 // Check if the user has the "Always prompt for download location" preference
491 // set. If so we prompt for most downloads except for the following scenarios:
492 // 1) Extension installation. Note that we only care here about the case where
493 // an extension is installed, not when one is downloaded with "save as...".
494 // 2) Filetypes marked "always open." If the user just wants this file opened,
495 // don't bother asking where to keep it.
496 if (download_prefs_->PromptForDownload() &&
497 !download_crx_util::IsExtensionDownload(*download_) &&
498 !extensions::Extension::IsExtension(filename) &&
499 !download_prefs_->IsAutoOpenEnabledBasedOnExtension(filename))
500 return true;
501
502 // Otherwise, don't prompt.
benjhayden 2013/04/26 15:07:37 Can you comment that we still could decide to prom
asanka 2013/04/26 17:02:21 Done.
503 return false;
504 }
505
506 bool DownloadTargetDeterminer::IsDangerousFile(PriorVisitsToReferrer visits) {
507 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
508 const bool is_extension_download =
509 download_crx_util::IsExtensionDownload(*download_);
510
511 // User-initiated extension downloads from pref-whitelisted sources are not
512 // considered dangerous.
513 if (download_->HasUserGesture() &&
514 is_extension_download &&
515 download_crx_util::OffStoreInstallAllowedByPrefs(
516 GetProfile(), *download_)) {
517 return false;
518 }
519
520 // Extensions that are not from the gallery are considered dangerous.
521 // When off-store install is disabled we skip this, since in this case, we
522 // will not offer to install the extension.
523 if (extensions::FeatureSwitch::easy_off_store_install()->IsEnabled() &&
524 is_extension_download &&
525 !extensions::WebstoreInstaller::GetAssociatedApproval(*download_)) {
526 return true;
527 }
528
529 // Anything the user has marked auto-open is OK if it's user-initiated.
530 if (download_prefs_->IsAutoOpenEnabledBasedOnExtension(virtual_path_) &&
531 download_->HasUserGesture())
532 return false;
533
534 switch (download_util::GetFileDangerLevel(virtual_path_.BaseName())) {
535 case download_util::NotDangerous:
benjhayden 2013/04/26 15:07:37 These enums look funny. Is this the right CL to fi
asanka 2013/04/26 17:02:21 I'll do a separate CL to fix them.
536 return false;
537
538 case download_util::AllowOnUserGesture:
539 // "Allow on user gesture" is OK when we have a user gesture and the
540 // hosting page has been visited before today.
541 if (download_->GetTransitionType() &
542 content::PAGE_TRANSITION_FROM_ADDRESS_BAR) {
543 return false;
544 }
545 return !download_->HasUserGesture() || visits == NO_VISITS_TO_REFERRER;
546
547 case download_util::Dangerous:
548 return true;
549 }
550 NOTREACHED();
551 return false;
552 }
553
554 void DownloadTargetDeterminer::OnDownloadDestroyed(
555 DownloadItem* download) {
556 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
557 DCHECK_EQ(download_, download);
558 CancelOnFailureAndDeleteSelf();
559 }
560
561 // static
562 void DownloadTargetDeterminer::Start(
563 content::DownloadItem* download,
564 DownloadPrefs* download_prefs,
565 const base::FilePath& last_selected_directory,
566 DownloadTargetDeterminerDelegate* delegate,
567 const content::DownloadTargetCallback& callback) {
568 // DownloadTargetDeterminer owns itself and will self destruct when the job is
569 // complete or the download item is destroyed. The callback is always invoked
570 // asynchronously.
571 new DownloadTargetDeterminer(download, download_prefs,
572 last_selected_directory, delegate, callback);
573 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698