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