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.
5 #include "chrome/browser/download/download_target_determiner.h"
7 #include "base/prefs/pref_service.h"
8 #include "base/rand_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/time/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/history/history_service.h"
16 #include "chrome/browser/history/history_service_factory.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/common/pref_names.h"
19 #include "content/public/browser/browser_context.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/download_interrupt_reasons.h"
22 #include "extensions/common/constants.h"
23 #include "grit/generated_resources.h"
24 #include "net/base/filename_util.h"
25 #include "net/base/mime_util.h"
26 #include "ui/base/l10n/l10n_util.h"
28 #if defined(ENABLE_EXTENSIONS)
29 #include "chrome/browser/extensions/webstore_installer.h"
30 #include "extensions/common/feature_switch.h"
33 #if defined(ENABLE_PLUGINS)
34 #include "chrome/browser/plugins/plugin_prefs.h"
35 #include "content/public/browser/plugin_service.h"
36 #include "content/public/common/webplugininfo.h"
40 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h"
43 using content::BrowserThread;
44 using content::DownloadItem;
48 const base::FilePath::CharType kCrdownloadSuffix[] =
49 FILE_PATH_LITERAL(".crdownload");
51 // Condenses the results from HistoryService::GetVisibleVisitCountToHost() to a
52 // single bool. A host is considered visited before if prior visible visits were
53 // found in history and the first such visit was earlier than the most recent
55 void VisitCountsToVisitedBefore(
56 const base::Callback<void(bool)>& callback,
59 base::Time first_visit) {
61 found_visits && count > 0 &&
62 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight()));
66 // Keeps track of whether Adobe Reader is up to date.
67 bool g_is_adobe_reader_up_to_date_ = false;
72 DownloadTargetInfo::DownloadTargetInfo()
73 : is_filetype_handled_safely(false) {}
75 DownloadTargetInfo::~DownloadTargetInfo() {}
77 DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() {
80 DownloadTargetDeterminer::DownloadTargetDeterminer(
81 DownloadItem* download,
82 const base::FilePath& initial_virtual_path,
83 DownloadPrefs* download_prefs,
84 DownloadTargetDeterminerDelegate* delegate,
85 const CompletionCallback& callback)
86 : next_state_(STATE_GENERATE_TARGET_PATH),
87 should_prompt_(false),
88 should_notify_extensions_(false),
89 create_target_directory_(false),
90 conflict_action_(DownloadPathReservationTracker::OVERWRITE),
91 danger_type_(download->GetDangerType()),
92 virtual_path_(initial_virtual_path),
93 is_filetype_handled_safely_(false),
95 is_resumption_(download_->GetLastReason() !=
96 content::DOWNLOAD_INTERRUPT_REASON_NONE &&
97 !initial_virtual_path.empty()),
98 download_prefs_(download_prefs),
100 completion_callback_(callback),
101 weak_ptr_factory_(this) {
102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
105 download_->AddObserver(this);
110 DownloadTargetDeterminer::~DownloadTargetDeterminer() {
111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
113 DCHECK(completion_callback_.is_null());
114 download_->RemoveObserver(this);
117 void DownloadTargetDeterminer::DoLoop() {
118 Result result = CONTINUE;
120 State current_state = next_state_;
121 next_state_ = STATE_NONE;
123 switch (current_state) {
124 case STATE_GENERATE_TARGET_PATH:
125 result = DoGenerateTargetPath();
127 case STATE_NOTIFY_EXTENSIONS:
128 result = DoNotifyExtensions();
130 case STATE_RESERVE_VIRTUAL_PATH:
131 result = DoReserveVirtualPath();
133 case STATE_PROMPT_USER_FOR_DOWNLOAD_PATH:
134 result = DoPromptUserForDownloadPath();
136 case STATE_DETERMINE_LOCAL_PATH:
137 result = DoDetermineLocalPath();
139 case STATE_DETERMINE_MIME_TYPE:
140 result = DoDetermineMimeType();
142 case STATE_DETERMINE_IF_HANDLED_SAFELY_BY_BROWSER:
143 result = DoDetermineIfHandledSafely();
145 case STATE_DETERMINE_IF_ADOBE_READER_UP_TO_DATE:
146 result = DoDetermineIfAdobeReaderUpToDate();
148 case STATE_CHECK_DOWNLOAD_URL:
149 result = DoCheckDownloadUrl();
151 case STATE_DETERMINE_INTERMEDIATE_PATH:
152 result = DoDetermineIntermediatePath();
154 case STATE_CHECK_VISITED_REFERRER_BEFORE:
155 result = DoCheckVisitedReferrerBefore();
161 } while (result == CONTINUE);
162 // Note that if a callback completes synchronously, the handler will still
163 // return QUIT_DOLOOP. In this case, an inner DoLoop() may complete the target
164 // determination and delete |this|.
166 if (result == COMPLETE)
167 ScheduleCallbackAndDeleteSelf();
170 DownloadTargetDeterminer::Result
171 DownloadTargetDeterminer::DoGenerateTargetPath() {
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
173 DCHECK(local_path_.empty());
174 DCHECK(!should_prompt_);
175 DCHECK(!should_notify_extensions_);
176 DCHECK_EQ(DownloadPathReservationTracker::OVERWRITE, conflict_action_);
177 bool is_forced_path = !download_->GetForcedFilePath().empty();
179 next_state_ = STATE_NOTIFY_EXTENSIONS;
181 if (!virtual_path_.empty() && HasPromptedForPath() && !is_forced_path) {
182 // The download is being resumed and the user has already been prompted for
183 // a path. Assume that it's okay to overwrite the file if there's a conflict
184 // and reuse the selection.
185 should_prompt_ = ShouldPromptForDownload(virtual_path_);
186 } else if (!is_forced_path) {
187 // If we don't have a forced path, we should construct a path for the
188 // download. Forced paths are only specified for programmatic downloads
189 // (WebStore, Drag&Drop). Treat the path as a virtual path. We will
190 // eventually determine whether this is a local path and if not, figure out
192 std::string default_filename(
193 l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME));
194 base::FilePath generated_filename = net::GenerateFileName(
196 download_->GetContentDisposition(),
197 GetProfile()->GetPrefs()->GetString(prefs::kDefaultCharset),
198 download_->GetSuggestedFilename(),
199 download_->GetMimeType(),
201 should_prompt_ = ShouldPromptForDownload(generated_filename);
202 base::FilePath target_directory;
203 if (should_prompt_) {
204 DCHECK(!download_prefs_->IsDownloadPathManaged());
205 // If the user is going to be prompted and the user has been prompted
206 // before, then always prefer the last directory that the user selected.
207 target_directory = download_prefs_->SaveFilePath();
209 target_directory = download_prefs_->DownloadPath();
211 virtual_path_ = target_directory.Append(generated_filename);
212 conflict_action_ = DownloadPathReservationTracker::UNIQUIFY;
213 should_notify_extensions_ = true;
215 virtual_path_ = download_->GetForcedFilePath();
216 // If this is a resumed download which was previously interrupted due to an
217 // issue with the forced path, the user is still not prompted. If the path
218 // supplied to a programmatic download is invalid, then the caller needs to
221 DCHECK(virtual_path_.IsAbsolute());
222 DVLOG(20) << "Generated virtual path: " << virtual_path_.AsUTF8Unsafe();
224 // If the download is DOA, don't bother going any further. This would be the
225 // case for a download that failed to initialize (e.g. the initial temporary
226 // file couldn't be created because both the downloads directory and the
227 // temporary directory are unwriteable).
229 // A virtual path is determined for DOA downloads for display purposes. This
230 // is why this check is performed here instead of at the start.
231 if (download_->GetState() != DownloadItem::IN_PROGRESS)
236 DownloadTargetDeterminer::Result
237 DownloadTargetDeterminer::DoNotifyExtensions() {
238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
239 DCHECK(!virtual_path_.empty());
241 next_state_ = STATE_RESERVE_VIRTUAL_PATH;
243 if (!should_notify_extensions_)
246 delegate_->NotifyExtensions(download_, virtual_path_,
247 base::Bind(&DownloadTargetDeterminer::NotifyExtensionsDone,
248 weak_ptr_factory_.GetWeakPtr()));
252 void DownloadTargetDeterminer::NotifyExtensionsDone(
253 const base::FilePath& suggested_path,
254 DownloadPathReservationTracker::FilenameConflictAction conflict_action) {
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
256 DVLOG(20) << "Extension suggested path: " << suggested_path.AsUTF8Unsafe();
258 // Extensions should not call back here more than once.
259 DCHECK_EQ(STATE_RESERVE_VIRTUAL_PATH, next_state_);
261 if (!suggested_path.empty()) {
262 // If an extension overrides the filename, then the target directory will be
263 // forced to download_prefs_->DownloadPath() since extensions cannot place
264 // downloaded files anywhere except there. This prevents subdirectories from
265 // accumulating: if an extension is allowed to say that a file should go in
266 // last_download_path/music/foo.mp3, then last_download_path will accumulate
267 // the subdirectory /music/ so that the next download may end up in
268 // Downloads/music/music/music/bar.mp3.
269 base::FilePath new_path(download_prefs_->DownloadPath().Append(
270 suggested_path).NormalizePathSeparators());
271 // Do not pass a mime type to GenerateSafeFileName so that it does not force
272 // the filename to have an extension if the (Chrome) extension does not
274 net::GenerateSafeFileName(std::string(), false, &new_path);
275 virtual_path_ = new_path;
276 create_target_directory_ = true;
278 // An extension may set conflictAction without setting filename.
279 if (conflict_action != DownloadPathReservationTracker::UNIQUIFY)
280 conflict_action_ = conflict_action;
285 DownloadTargetDeterminer::Result
286 DownloadTargetDeterminer::DoReserveVirtualPath() {
287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
288 DCHECK(!virtual_path_.empty());
290 next_state_ = STATE_PROMPT_USER_FOR_DOWNLOAD_PATH;
292 delegate_->ReserveVirtualPath(
293 download_, virtual_path_, create_target_directory_, conflict_action_,
294 base::Bind(&DownloadTargetDeterminer::ReserveVirtualPathDone,
295 weak_ptr_factory_.GetWeakPtr()));
299 void DownloadTargetDeterminer::ReserveVirtualPathDone(
300 const base::FilePath& path, bool verified) {
301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
302 DVLOG(20) << "Reserved path: " << path.AsUTF8Unsafe()
303 << " Verified:" << verified;
304 DCHECK_EQ(STATE_PROMPT_USER_FOR_DOWNLOAD_PATH, next_state_);
306 should_prompt_ = (should_prompt_ || !verified);
307 virtual_path_ = path;
311 DownloadTargetDeterminer::Result
312 DownloadTargetDeterminer::DoPromptUserForDownloadPath() {
313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
314 DCHECK(!virtual_path_.empty());
316 next_state_ = STATE_DETERMINE_LOCAL_PATH;
318 if (should_prompt_) {
319 delegate_->PromptUserForDownloadPath(
322 base::Bind(&DownloadTargetDeterminer::PromptUserForDownloadPathDone,
323 weak_ptr_factory_.GetWeakPtr()));
329 void DownloadTargetDeterminer::PromptUserForDownloadPathDone(
330 const base::FilePath& virtual_path) {
331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
332 DVLOG(20) << "User selected path:" << virtual_path.AsUTF8Unsafe();
333 if (virtual_path.empty()) {
334 CancelOnFailureAndDeleteSelf();
337 DCHECK_EQ(STATE_DETERMINE_LOCAL_PATH, next_state_);
339 virtual_path_ = virtual_path;
340 download_prefs_->SetSaveFilePath(virtual_path_.DirName());
344 DownloadTargetDeterminer::Result
345 DownloadTargetDeterminer::DoDetermineLocalPath() {
346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
347 DCHECK(!virtual_path_.empty());
348 DCHECK(local_path_.empty());
350 next_state_ = STATE_DETERMINE_MIME_TYPE;
352 delegate_->DetermineLocalPath(
355 base::Bind(&DownloadTargetDeterminer::DetermineLocalPathDone,
356 weak_ptr_factory_.GetWeakPtr()));
360 void DownloadTargetDeterminer::DetermineLocalPathDone(
361 const base::FilePath& local_path) {
362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
363 DVLOG(20) << "Local path: " << local_path.AsUTF8Unsafe();
364 if (local_path.empty()) {
365 // Path subsitution failed.
366 CancelOnFailureAndDeleteSelf();
369 DCHECK_EQ(STATE_DETERMINE_MIME_TYPE, next_state_);
371 local_path_ = local_path;
375 DownloadTargetDeterminer::Result
376 DownloadTargetDeterminer::DoDetermineMimeType() {
377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
378 DCHECK(!virtual_path_.empty());
379 DCHECK(!local_path_.empty());
380 DCHECK(mime_type_.empty());
382 next_state_ = STATE_DETERMINE_IF_HANDLED_SAFELY_BY_BROWSER;
384 if (virtual_path_ == local_path_) {
385 delegate_->GetFileMimeType(
387 base::Bind(&DownloadTargetDeterminer::DetermineMimeTypeDone,
388 weak_ptr_factory_.GetWeakPtr()));
394 void DownloadTargetDeterminer::DetermineMimeTypeDone(
395 const std::string& mime_type) {
396 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
397 DVLOG(20) << "MIME type: " << mime_type;
398 DCHECK_EQ(STATE_DETERMINE_IF_HANDLED_SAFELY_BY_BROWSER, next_state_);
400 mime_type_ = mime_type;
404 #if defined(ENABLE_PLUGINS)
405 // The code below is used by DoDetermineIfHandledSafely to determine if the
406 // file type is handled by a sandboxed plugin.
409 void InvokeClosureAfterGetPluginCallback(
410 const base::Closure& closure,
411 const std::vector<content::WebPluginInfo>& unused) {
415 enum ActionOnStalePluginList {
416 RETRY_IF_STALE_PLUGIN_LIST,
417 IGNORE_IF_STALE_PLUGIN_LIST
420 void IsHandledBySafePlugin(content::ResourceContext* resource_context,
422 const std::string& mime_type,
423 ActionOnStalePluginList stale_plugin_action,
424 const base::Callback<void(bool)>& callback) {
425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
426 DCHECK(!mime_type.empty());
427 using content::WebPluginInfo;
429 std::string actual_mime_type;
430 bool is_stale = false;
431 WebPluginInfo plugin_info;
433 content::PluginService* plugin_service =
434 content::PluginService::GetInstance();
435 bool plugin_found = plugin_service->GetPluginInfo(-1, -1, resource_context,
436 url, GURL(), mime_type,
440 if (is_stale && stale_plugin_action == RETRY_IF_STALE_PLUGIN_LIST) {
441 // The GetPlugins call causes the plugin list to be refreshed. Once that's
442 // done we can retry the GetPluginInfo call. We break out of this cycle
443 // after a single retry in order to avoid retrying indefinitely.
444 plugin_service->GetPlugins(
445 base::Bind(&InvokeClosureAfterGetPluginCallback,
446 base::Bind(&IsHandledBySafePlugin,
450 IGNORE_IF_STALE_PLUGIN_LIST,
454 // In practice, we assume that retrying once is enough.
456 bool is_handled_safely =
458 (plugin_info.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS ||
459 plugin_info.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS);
460 BrowserThread::PostTask(
461 BrowserThread::UI, FROM_HERE, base::Bind(callback, is_handled_safely));
465 #endif // defined(ENABLE_PLUGINS)
467 DownloadTargetDeterminer::Result
468 DownloadTargetDeterminer::DoDetermineIfHandledSafely() {
469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
470 DCHECK(!virtual_path_.empty());
471 DCHECK(!local_path_.empty());
472 DCHECK(!is_filetype_handled_safely_);
474 next_state_ = STATE_DETERMINE_IF_ADOBE_READER_UP_TO_DATE;
476 if (mime_type_.empty())
479 if (net::IsSupportedMimeType(mime_type_)) {
480 is_filetype_handled_safely_ = true;
484 #if defined(ENABLE_PLUGINS)
485 BrowserThread::PostTask(
489 &IsHandledBySafePlugin,
490 GetProfile()->GetResourceContext(),
491 net::FilePathToFileURL(local_path_),
493 RETRY_IF_STALE_PLUGIN_LIST,
494 base::Bind(&DownloadTargetDeterminer::DetermineIfHandledSafelyDone,
495 weak_ptr_factory_.GetWeakPtr())));
502 #if defined(ENABLE_PLUGINS)
503 void DownloadTargetDeterminer::DetermineIfHandledSafelyDone(
504 bool is_handled_safely) {
505 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
506 DVLOG(20) << "Is file type handled safely: " << is_filetype_handled_safely_;
507 DCHECK_EQ(STATE_DETERMINE_IF_ADOBE_READER_UP_TO_DATE, next_state_);
508 is_filetype_handled_safely_ = is_handled_safely;
513 DownloadTargetDeterminer::Result
514 DownloadTargetDeterminer::DoDetermineIfAdobeReaderUpToDate() {
515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
517 next_state_ = STATE_CHECK_DOWNLOAD_URL;
520 if (!local_path_.MatchesExtension(FILE_PATH_LITERAL(".pdf")))
522 if (!IsAdobeReaderDefaultPDFViewer()) {
523 g_is_adobe_reader_up_to_date_ = false;
527 base::PostTaskAndReplyWithResult(
528 BrowserThread::GetBlockingPool(),
530 base::Bind(&::IsAdobeReaderUpToDate),
531 base::Bind(&DownloadTargetDeterminer::DetermineIfAdobeReaderUpToDateDone,
532 weak_ptr_factory_.GetWeakPtr()));
540 void DownloadTargetDeterminer::DetermineIfAdobeReaderUpToDateDone(
541 bool adobe_reader_up_to_date) {
542 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
543 DVLOG(20) << "Is Adobe Reader Up To Date: " << adobe_reader_up_to_date;
544 DCHECK_EQ(STATE_CHECK_DOWNLOAD_URL, next_state_);
545 g_is_adobe_reader_up_to_date_ = adobe_reader_up_to_date;
550 DownloadTargetDeterminer::Result
551 DownloadTargetDeterminer::DoCheckDownloadUrl() {
552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
553 DCHECK(!virtual_path_.empty());
554 next_state_ = STATE_CHECK_VISITED_REFERRER_BEFORE;
555 delegate_->CheckDownloadUrl(
558 base::Bind(&DownloadTargetDeterminer::CheckDownloadUrlDone,
559 weak_ptr_factory_.GetWeakPtr()));
563 void DownloadTargetDeterminer::CheckDownloadUrlDone(
564 content::DownloadDangerType danger_type) {
565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
566 DVLOG(20) << "URL Check Result:" << danger_type;
567 DCHECK_EQ(STATE_CHECK_VISITED_REFERRER_BEFORE, next_state_);
568 danger_type_ = danger_type;
572 DownloadTargetDeterminer::Result
573 DownloadTargetDeterminer::DoCheckVisitedReferrerBefore() {
574 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
576 next_state_ = STATE_DETERMINE_INTERMEDIATE_PATH;
578 // Checking if there are prior visits to the referrer is only necessary if the
579 // danger level of the download depends on the file type. This excludes cases
580 // where the download has already been deemed dangerous, or where the user is
581 // going to be prompted or where this is a programmatic download.
582 if (danger_type_ != content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
586 // IsDangerousFile(VISITED_REFERRER) => IsDangerousFile(NO_VISITS_...)
587 // I.e. having visited a referrer only lowers a file's danger level.
588 if (IsDangerousFile(NO_VISITS_TO_REFERRER)) {
589 // Only need to ping the history DB if the download would be considered safe
590 // if there are prior visits and is considered dangerous otherwise.
591 if (!IsDangerousFile(VISITED_REFERRER)) {
592 // HistoryServiceFactory redirects incognito profiles to on-record
593 // profiles. There's no history for on-record profiles in unit_tests.
594 HistoryService* history_service = HistoryServiceFactory::GetForProfile(
595 GetProfile(), Profile::EXPLICIT_ACCESS);
597 if (history_service && download_->GetReferrerUrl().is_valid()) {
598 history_service->GetVisibleVisitCountToHost(
599 download_->GetReferrerUrl(),
601 &VisitCountsToVisitedBefore,
603 &DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone,
604 weak_ptr_factory_.GetWeakPtr())),
610 // If the danger level doesn't depend on having visited the refererrer URL
611 // or if original profile doesn't have a HistoryService or the referrer url
612 // is invalid, then assume the referrer has not been visited before.
613 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE;
618 void DownloadTargetDeterminer::CheckVisitedReferrerBeforeDone(
619 bool visited_referrer_before) {
620 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
621 DCHECK_EQ(STATE_DETERMINE_INTERMEDIATE_PATH, next_state_);
623 visited_referrer_before ? VISITED_REFERRER : NO_VISITS_TO_REFERRER))
624 danger_type_ = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE;
628 DownloadTargetDeterminer::Result
629 DownloadTargetDeterminer::DoDetermineIntermediatePath() {
630 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
631 DCHECK(!virtual_path_.empty());
632 DCHECK(!local_path_.empty());
633 DCHECK(intermediate_path_.empty());
634 DCHECK(!virtual_path_.MatchesExtension(kCrdownloadSuffix));
635 DCHECK(!local_path_.MatchesExtension(kCrdownloadSuffix));
637 next_state_ = STATE_NONE;
639 // Note that the intermediate filename is always uniquified (i.e. if a file by
640 // the same name exists, it is never overwritten). Therefore the code below
641 // does not attempt to find a name that doesn't conflict with an existing
644 // If the actual target of the download is a virtual path, then the local path
645 // is considered to point to a temporary path. A separate intermediate path is
646 // unnecessary since the local path already serves that purpose.
647 if (virtual_path_.BaseName() != local_path_.BaseName()) {
648 intermediate_path_ = local_path_;
652 // If the download has a forced path and is safe, then just use the
653 // target path. In practice the temporary download file that was created prior
654 // to download filename determination is already named
655 // download_->GetForcedFilePath().
656 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS &&
657 !download_->GetForcedFilePath().empty()) {
658 DCHECK_EQ(download_->GetForcedFilePath().value(), local_path_.value());
659 intermediate_path_ = local_path_;
663 // Other safe downloads get a .crdownload suffix for their intermediate name.
664 if (danger_type_ == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
665 intermediate_path_ = GetCrDownloadPath(local_path_);
669 // If this is a resumed download, then re-use the existing intermediate path
670 // if one is available. A resumed download shouldn't cause a non-dangerous
671 // download to be considered dangerous upon resumption. Therefore the
672 // intermediate file should already be in the correct form.
673 if (is_resumption_ && !download_->GetFullPath().empty() &&
674 local_path_.DirName() == download_->GetFullPath().DirName()) {
675 DCHECK_NE(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
676 download_->GetDangerType());
677 DCHECK_EQ(kCrdownloadSuffix, download_->GetFullPath().Extension());
678 intermediate_path_ = download_->GetFullPath();
682 // Dangerous downloads receive a random intermediate name that looks like:
683 // 'Unconfirmed <random>.crdownload'.
684 const base::FilePath::CharType kUnconfirmedFormatSuffix[] =
685 FILE_PATH_LITERAL(" %d.crdownload");
686 // Range of the <random> uniquifier.
687 const int kUnconfirmedUniquifierRange = 1000000;
689 base::string16 unconfirmed_format =
690 l10n_util::GetStringUTF16(IDS_DOWNLOAD_UNCONFIRMED_PREFIX);
692 std::string unconfirmed_format =
693 l10n_util::GetStringUTF8(IDS_DOWNLOAD_UNCONFIRMED_PREFIX);
695 unconfirmed_format.append(kUnconfirmedFormatSuffix);
697 base::FilePath::StringType file_name = base::StringPrintf(
698 unconfirmed_format.c_str(),
699 base::RandInt(0, kUnconfirmedUniquifierRange));
700 intermediate_path_ = local_path_.DirName().Append(file_name);
704 void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() {
706 DVLOG(20) << "Scheduling callback. Virtual:" << virtual_path_.AsUTF8Unsafe()
707 << " Local:" << local_path_.AsUTF8Unsafe()
708 << " Intermediate:" << intermediate_path_.AsUTF8Unsafe()
709 << " Should prompt:" << should_prompt_
710 << " Danger type:" << danger_type_;
711 scoped_ptr<DownloadTargetInfo> target_info(new DownloadTargetInfo);
713 target_info->target_path = local_path_;
714 target_info->target_disposition =
715 (HasPromptedForPath() || should_prompt_
716 ? DownloadItem::TARGET_DISPOSITION_PROMPT
717 : DownloadItem::TARGET_DISPOSITION_OVERWRITE);
718 target_info->danger_type = danger_type_;
719 target_info->intermediate_path = intermediate_path_;
720 target_info->mime_type = mime_type_;
721 target_info->is_filetype_handled_safely = is_filetype_handled_safely_;
723 base::MessageLoop::current()->PostTask(
724 FROM_HERE, base::Bind(completion_callback_, base::Passed(&target_info)));
725 completion_callback_.Reset();
729 void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() {
730 // Path substitution failed.
731 virtual_path_.clear();
733 intermediate_path_.clear();
734 ScheduleCallbackAndDeleteSelf();
737 Profile* DownloadTargetDeterminer::GetProfile() {
738 DCHECK(download_->GetBrowserContext());
739 return Profile::FromBrowserContext(download_->GetBrowserContext());
742 bool DownloadTargetDeterminer::ShouldPromptForDownload(
743 const base::FilePath& filename) const {
744 if (is_resumption_) {
745 // For resumed downloads, if the target disposition or prefs require
746 // prompting, the user has already been prompted. Try to respect the user's
747 // selection, unless we've discovered that the target path cannot be used
749 content::DownloadInterruptReason reason = download_->GetLastReason();
750 return (reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED ||
751 reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE ||
752 reason == content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE);
755 // If the download path is forced, don't prompt.
756 if (!download_->GetForcedFilePath().empty()) {
757 // 'Save As' downloads shouldn't have a forced path.
758 DCHECK(DownloadItem::TARGET_DISPOSITION_PROMPT !=
759 download_->GetTargetDisposition());
763 // Don't ask where to save if the download path is managed. Even if the user
764 // wanted to be prompted for "all" downloads, or if this was a 'Save As'
766 if (download_prefs_->IsDownloadPathManaged())
769 // Prompt if this is a 'Save As' download.
770 if (download_->GetTargetDisposition() ==
771 DownloadItem::TARGET_DISPOSITION_PROMPT)
774 // Check if the user has the "Always prompt for download location" preference
775 // set. If so we prompt for most downloads except for the following scenarios:
776 // 1) Extension installation. Note that we only care here about the case where
777 // an extension is installed, not when one is downloaded with "save as...".
778 // 2) Filetypes marked "always open." If the user just wants this file opened,
779 // don't bother asking where to keep it.
780 if (download_prefs_->PromptForDownload() &&
781 !download_crx_util::IsExtensionDownload(*download_) &&
782 !filename.MatchesExtension(extensions::kExtensionFileExtension) &&
783 !download_prefs_->IsAutoOpenEnabledBasedOnExtension(filename))
786 // Otherwise, don't prompt. Note that the user might still be prompted if
787 // there are unresolved conflicts during path reservation (e.g. due to the
788 // target path being unwriteable or because there are too many conflicting
789 // files), or if an extension signals that the user be prompted on a filename
794 bool DownloadTargetDeterminer::HasPromptedForPath() const {
795 return (is_resumption_ && download_->GetTargetDisposition() ==
796 DownloadItem::TARGET_DISPOSITION_PROMPT);
799 bool DownloadTargetDeterminer::IsDangerousFile(PriorVisitsToReferrer visits) {
800 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
802 // If the user has has been prompted or will be, assume that the user has
803 // approved the download. A programmatic download is considered safe unless it
805 if (HasPromptedForPath() || should_prompt_ ||
806 !download_->GetForcedFilePath().empty())
809 const bool is_extension_download =
810 download_crx_util::IsExtensionDownload(*download_);
812 // User-initiated extension downloads from pref-whitelisted sources are not
813 // considered dangerous.
814 if (download_->HasUserGesture() &&
815 is_extension_download &&
816 download_crx_util::OffStoreInstallAllowedByPrefs(
817 GetProfile(), *download_)) {
821 #if defined(ENABLE_EXTENSIONS)
822 // Extensions that are not from the gallery are considered dangerous.
823 // When off-store install is disabled we skip this, since in this case, we
824 // will not offer to install the extension.
825 if (extensions::FeatureSwitch::easy_off_store_install()->IsEnabled() &&
826 is_extension_download &&
827 !extensions::WebstoreInstaller::GetAssociatedApproval(*download_)) {
832 // Anything the user has marked auto-open is OK if it's user-initiated.
833 if (download_prefs_->IsAutoOpenEnabledBasedOnExtension(virtual_path_) &&
834 download_->HasUserGesture())
837 switch (download_util::GetFileDangerLevel(virtual_path_.BaseName())) {
838 case download_util::NOT_DANGEROUS:
841 case download_util::ALLOW_ON_USER_GESTURE:
842 // "Allow on user gesture" is OK when we have a user gesture and the
843 // hosting page has been visited before today.
844 if (download_->GetTransitionType() &
845 content::PAGE_TRANSITION_FROM_ADDRESS_BAR) {
848 return !download_->HasUserGesture() || visits == NO_VISITS_TO_REFERRER;
850 case download_util::DANGEROUS:
857 void DownloadTargetDeterminer::OnDownloadDestroyed(
858 DownloadItem* download) {
859 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
860 DCHECK_EQ(download_, download);
861 CancelOnFailureAndDeleteSelf();
865 void DownloadTargetDeterminer::Start(content::DownloadItem* download,
866 const base::FilePath& initial_virtual_path,
867 DownloadPrefs* download_prefs,
868 DownloadTargetDeterminerDelegate* delegate,
869 const CompletionCallback& callback) {
870 // DownloadTargetDeterminer owns itself and will self destruct when the job is
871 // complete or the download item is destroyed. The callback is always invoked
873 new DownloadTargetDeterminer(download, initial_virtual_path, download_prefs,
878 base::FilePath DownloadTargetDeterminer::GetCrDownloadPath(
879 const base::FilePath& suggested_path) {
880 return base::FilePath(suggested_path.value() + kCrdownloadSuffix);
885 bool DownloadTargetDeterminer::IsAdobeReaderUpToDate() {
886 return g_is_adobe_reader_up_to_date_;