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

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

Powered by Google App Engine
This is Rietveld 408576698