Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / download / download_target_determiner.cc
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