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