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
43using content::BrowserThread;
44using content::DownloadItem;
45
46namespace {
47
48const 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.
55void 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.
67bool g_is_adobe_reader_up_to_date_ = false;
68#endif
69
70}  // namespace
71
72DownloadTargetInfo::DownloadTargetInfo()
73    : is_filetype_handled_safely(false) {}
74
75DownloadTargetInfo::~DownloadTargetInfo() {}
76
77DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() {
78}
79
80DownloadTargetDeterminer::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
111DownloadTargetDeterminer::~DownloadTargetDeterminer() {
112  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
113  DCHECK(download_);
114  DCHECK(completion_callback_.is_null());
115  download_->RemoveObserver(this);
116}
117
118void 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
171DownloadTargetDeterminer::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
237DownloadTargetDeterminer::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
253void 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
286DownloadTargetDeterminer::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
300void 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
312DownloadTargetDeterminer::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
330void 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
345DownloadTargetDeterminer::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
361void 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
376DownloadTargetDeterminer::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
395void 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.
408namespace {
409
410void InvokeClosureAfterGetPluginCallback(
411    const base::Closure& closure,
412    const std::vector<content::WebPluginInfo>& unused) {
413  closure.Run();
414}
415
416enum ActionOnStalePluginList {
417  RETRY_IF_STALE_PLUGIN_LIST,
418  IGNORE_IF_STALE_PLUGIN_LIST
419};
420
421void 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
468DownloadTargetDeterminer::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)
504void 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
514DownloadTargetDeterminer::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)
541void 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
551DownloadTargetDeterminer::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
564void 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
573DownloadTargetDeterminer::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
620void 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
633DownloadTargetDeterminer::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
709void 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
736void DownloadTargetDeterminer::CancelOnFailureAndDeleteSelf() {
737  // Path substitution failed.
738  virtual_path_.clear();
739  local_path_.clear();
740  intermediate_path_.clear();
741  ScheduleCallbackAndDeleteSelf();
742}
743
744Profile* DownloadTargetDeterminer::GetProfile() {
745  DCHECK(download_->GetBrowserContext());
746  return Profile::FromBrowserContext(download_->GetBrowserContext());
747}
748
749bool 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
801bool DownloadTargetDeterminer::HasPromptedForPath() const {
802  return (is_resumption_ && download_->GetTargetDisposition() ==
803                                DownloadItem::TARGET_DISPOSITION_PROMPT);
804}
805
806bool 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
864void DownloadTargetDeterminer::OnDownloadDestroyed(
865    DownloadItem* download) {
866  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
867  DCHECK_EQ(download_, download);
868  CancelOnFailureAndDeleteSelf();
869}
870
871// static
872void 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
885base::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
892bool DownloadTargetDeterminer::IsAdobeReaderUpToDate() {
893  return g_is_adobe_reader_up_to_date_;
894}
895#endif
896