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