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