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