Override server-side simple-cache trial with commandline switches.
[chromium-blink-merge.git] / chrome / browser / download / chrome_download_manager_delegate.cc
blob5482a50688408594183bc7c0e604e48a4e9fd63e
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/download/chrome_download_manager_delegate.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/file_util.h"
13 #include "base/prefs/pref_member.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/rand_util.h"
16 #include "base/stringprintf.h"
17 #include "base/time.h"
18 #include "base/utf_string_conversions.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/download/download_completion_blocker.h"
21 #include "chrome/browser/download/download_crx_util.h"
22 #include "chrome/browser/download/download_file_picker.h"
23 #include "chrome/browser/download/download_history.h"
24 #include "chrome/browser/download/download_path_reservation_tracker.h"
25 #include "chrome/browser/download/download_prefs.h"
26 #include "chrome/browser/download/download_service.h"
27 #include "chrome/browser/download/download_service_factory.h"
28 #include "chrome/browser/download/download_target_determiner.h"
29 #include "chrome/browser/download/download_util.h"
30 #include "chrome/browser/download/save_package_file_picker.h"
31 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
32 #include "chrome/browser/extensions/crx_installer.h"
33 #include "chrome/browser/platform_util.h"
34 #include "chrome/browser/profiles/profile.h"
35 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
36 #include "chrome/common/chrome_notification_types.h"
37 #include "chrome/common/extensions/extension.h"
38 #include "chrome/common/pref_names.h"
39 #include "components/user_prefs/pref_registry_syncable.h"
40 #include "content/public/browser/download_item.h"
41 #include "content/public/browser/download_manager.h"
42 #include "content/public/browser/notification_source.h"
44 #if defined(OS_CHROMEOS)
45 #include "chrome/browser/chromeos/drive/download_handler.h"
46 #include "chrome/browser/chromeos/drive/file_system_util.h"
47 #include "chrome/browser/download/save_package_file_picker_chromeos.h"
48 #endif
50 using content::BrowserContext;
51 using content::BrowserThread;
52 using content::DownloadId;
53 using content::DownloadItem;
54 using content::DownloadManager;
55 using safe_browsing::DownloadProtectionService;
57 namespace {
59 // String pointer used for identifying safebrowing data associated with
60 // a download item.
61 static const char safe_browsing_id[] = "Safe Browsing ID";
63 // The state of a safebrowsing check.
64 class SafeBrowsingState : public DownloadCompletionBlocker {
65 public:
66 SafeBrowsingState()
67 : verdict_(DownloadProtectionService::SAFE) {
70 virtual ~SafeBrowsingState();
72 // The verdict that we got from calling CheckClientDownload. Only valid to
73 // call if |is_complete()|.
74 DownloadProtectionService::DownloadCheckResult verdict() const {
75 return verdict_;
78 void SetVerdict(DownloadProtectionService::DownloadCheckResult result) {
79 verdict_ = result;
80 CompleteDownload();
83 private:
84 DownloadProtectionService::DownloadCheckResult verdict_;
86 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingState);
89 SafeBrowsingState::~SafeBrowsingState() {}
91 // Returns a file path in the form that is expected by
92 // platform_util::OpenItem/ShowItemInFolder, including any transformation
93 // required for download abstractions layered on top of the core system,
94 // e.g. download to Drive.
95 base::FilePath GetPlatformDownloadPath(Profile* profile,
96 const DownloadItem* download) {
97 #if defined(OS_CHROMEOS)
98 drive::DownloadHandler* drive_download_handler =
99 drive::DownloadHandler::GetForProfile(profile);
100 if (drive_download_handler &&
101 drive_download_handler->IsDriveDownload(download))
102 return drive_download_handler->GetTargetPath(download);
103 #endif
104 // The caller wants to open the download or show it in a file browser. The
105 // download could be in one of three states:
106 // - Complete: The path we want is GetTargetFilePath().
107 // - Not complete, but there's an intermediate file: GetFullPath() will be
108 // non-empty and is the location of the intermediate file. Since no target
109 // file exits yet, use GetFullPath(). This should only happen during
110 // ShowDownloadInShell().
111 // - Not Complete, and there's no intermediate file: GetFullPath() will be
112 // empty. This shouldn't happen since CanShowInFolder() returns false and
113 // this function shouldn't have been called.
114 if (download->IsComplete()) {
115 DCHECK(!download->GetTargetFilePath().empty());
116 return download->GetTargetFilePath();
119 DCHECK(!download->GetFullPath().empty());
120 return download->GetFullPath();
123 // Callback invoked by DownloadProtectionService::CheckClientDownload.
124 // |is_content_check_supported| is true if the SB service supports scanning the
125 // download for malicious content.
126 // |callback| is invoked with a danger type determined as follows:
128 // Danger type is (in order of preference):
129 // * DANGEROUS_URL, if the URL is a known malware site.
130 // * MAYBE_DANGEROUS_CONTENT, if the content will be scanned for
131 // malware. I.e. |is_content_check_supported| is true.
132 // * NOT_DANGEROUS.
133 void CheckDownloadUrlDone(
134 const DownloadTargetDeterminerDelegate::CheckDownloadUrlCallback& callback,
135 bool is_content_check_supported,
136 DownloadProtectionService::DownloadCheckResult result) {
137 content::DownloadDangerType danger_type;
138 if (result == DownloadProtectionService::SAFE) {
139 // If this type of files is handled by the enhanced SafeBrowsing download
140 // protection, mark it as potentially dangerous content until we are done
141 // with scanning it.
142 if (is_content_check_supported)
143 danger_type = content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT;
144 else
145 danger_type = content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
146 } else {
147 // If the URL is malicious, we'll use that as the danger type. The results
148 // of the content check, if one is performed, will be ignored.
149 danger_type = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL;
151 callback.Run(danger_type);
154 } // namespace
156 // static
157 void ChromeDownloadManagerDelegate::RegisterUserPrefs(
158 user_prefs::PrefRegistrySyncable* registry) {
159 const base::FilePath& default_download_path =
160 download_util::GetDefaultDownloadDirectory();
161 registry->RegisterFilePathPref(
162 prefs::kSaveFileDefaultDirectory,
163 default_download_path,
164 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
167 ChromeDownloadManagerDelegate::ChromeDownloadManagerDelegate(Profile* profile)
168 : profile_(profile),
169 next_download_id_(0),
170 download_prefs_(new DownloadPrefs(profile)) {
173 ChromeDownloadManagerDelegate::~ChromeDownloadManagerDelegate() {
176 void ChromeDownloadManagerDelegate::SetDownloadManager(DownloadManager* dm) {
177 download_manager_ = dm;
180 void ChromeDownloadManagerDelegate::Shutdown() {
181 download_prefs_.reset();
184 DownloadId ChromeDownloadManagerDelegate::GetNextId() {
185 if (!profile_->IsOffTheRecord())
186 return DownloadId(this, next_download_id_++);
188 return BrowserContext::GetDownloadManager(profile_->GetOriginalProfile())->
189 GetDelegate()->GetNextId();
192 bool ChromeDownloadManagerDelegate::DetermineDownloadTarget(
193 DownloadItem* download,
194 const content::DownloadTargetCallback& callback) {
195 DownloadTargetDeterminer::Start(download,
196 download_prefs_.get(),
197 last_download_path_,
198 this,
199 callback);
200 return true;
203 bool ChromeDownloadManagerDelegate::ShouldOpenFileBasedOnExtension(
204 const base::FilePath& path) {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
206 if (path.Extension().empty())
207 return false;
208 // TODO(asanka): This determination is done based on |path|, while
209 // ShouldOpenDownload() detects extension downloads based on the
210 // characteristics of the download. Reconcile this. http://crbug.com/167702
211 if (extensions::Extension::IsExtension(path))
212 return false;
213 return download_prefs_->IsAutoOpenEnabledBasedOnExtension(path);
216 // static
217 void ChromeDownloadManagerDelegate::DisableSafeBrowsing(DownloadItem* item) {
218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
219 #if defined(FULL_SAFE_BROWSING)
220 SafeBrowsingState* state = static_cast<SafeBrowsingState*>(
221 item->GetUserData(&safe_browsing_id));
222 if (!state) {
223 state = new SafeBrowsingState();
224 item->SetUserData(&safe_browsing_id, state);
226 state->SetVerdict(DownloadProtectionService::SAFE);
227 #endif
230 bool ChromeDownloadManagerDelegate::IsDownloadReadyForCompletion(
231 DownloadItem* item,
232 const base::Closure& internal_complete_callback) {
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
234 #if defined(FULL_SAFE_BROWSING)
235 SafeBrowsingState* state = static_cast<SafeBrowsingState*>(
236 item->GetUserData(&safe_browsing_id));
237 if (!state) {
238 // Begin the safe browsing download protection check.
239 DownloadProtectionService* service = GetDownloadProtectionService();
240 if (service) {
241 VLOG(2) << __FUNCTION__ << "() Start SB download check for download = "
242 << item->DebugString(false);
243 state = new SafeBrowsingState();
244 state->set_callback(internal_complete_callback);
245 item->SetUserData(&safe_browsing_id, state);
246 service->CheckClientDownload(
247 item,
248 base::Bind(
249 &ChromeDownloadManagerDelegate::CheckClientDownloadDone,
250 this,
251 item->GetId()));
252 return false;
254 } else if (!state->is_complete()) {
255 // Don't complete the download until we have an answer.
256 state->set_callback(internal_complete_callback);
257 return false;
259 #endif
260 return true;
263 void ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal(
264 int download_id,
265 const base::Closure& user_complete_callback) {
266 DownloadItem* item = download_manager_->GetDownload(download_id);
267 if (!item)
268 return;
269 if (ShouldCompleteDownload(item, user_complete_callback))
270 user_complete_callback.Run();
273 bool ChromeDownloadManagerDelegate::ShouldCompleteDownload(
274 DownloadItem* item,
275 const base::Closure& user_complete_callback) {
276 return IsDownloadReadyForCompletion(item, base::Bind(
277 &ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal,
278 this, item->GetId(), user_complete_callback));
281 bool ChromeDownloadManagerDelegate::ShouldOpenDownload(
282 DownloadItem* item, const content::DownloadOpenDelayedCallback& callback) {
283 if (download_crx_util::IsExtensionDownload(*item)) {
284 scoped_refptr<extensions::CrxInstaller> crx_installer =
285 download_crx_util::OpenChromeExtension(profile_, *item);
287 // CRX_INSTALLER_DONE will fire when the install completes. At that
288 // time, Observe() will call the passed callback.
289 registrar_.Add(
290 this,
291 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
292 content::Source<extensions::CrxInstaller>(crx_installer.get()));
294 crx_installers_[crx_installer.get()] = callback;
295 // The status text and percent complete indicator will change now
296 // that we are installing a CRX. Update observers so that they pick
297 // up the change.
298 item->UpdateObservers();
299 return false;
302 return true;
305 bool ChromeDownloadManagerDelegate::GenerateFileHash() {
306 #if defined(FULL_SAFE_BROWSING)
307 return profile_->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled) &&
308 g_browser_process->safe_browsing_service()->DownloadBinHashNeeded();
309 #else
310 return false;
311 #endif
314 void ChromeDownloadManagerDelegate::GetSaveDir(
315 BrowserContext* browser_context,
316 base::FilePath* website_save_dir,
317 base::FilePath* download_save_dir,
318 bool* skip_dir_check) {
319 Profile* profile = Profile::FromBrowserContext(browser_context);
320 PrefService* prefs = profile->GetPrefs();
322 // Check whether the preference for the preferred directory for
323 // saving file has been explicitly set. If not, and the preference
324 // for the default download directory has been set, initialize it
325 // with the latter. Note that the defaults for both are the same.
326 const PrefService::Preference* download_default_directory =
327 prefs->FindPreference(prefs::kDownloadDefaultDirectory);
328 if (!download_default_directory->IsDefaultValue() &&
329 prefs->FindPreference(
330 prefs::kSaveFileDefaultDirectory)->IsDefaultValue()) {
331 prefs->Set(prefs::kSaveFileDefaultDirectory,
332 *(download_default_directory->GetValue()));
335 // Get the directory from preference.
336 *website_save_dir = prefs->GetFilePath(prefs::kSaveFileDefaultDirectory);
337 DCHECK(!website_save_dir->empty());
339 *download_save_dir = prefs->GetFilePath(prefs::kDownloadDefaultDirectory);
341 *skip_dir_check = false;
342 #if defined(OS_CHROMEOS)
343 *skip_dir_check = drive::util::IsUnderDriveMountPoint(*website_save_dir);
344 #endif
347 void ChromeDownloadManagerDelegate::ChooseSavePath(
348 content::WebContents* web_contents,
349 const base::FilePath& suggested_path,
350 const base::FilePath::StringType& default_extension,
351 bool can_save_as_complete,
352 const content::SavePackagePathPickedCallback& callback) {
353 // Deletes itself.
354 #if defined(OS_CHROMEOS)
355 new SavePackageFilePickerChromeOS(
356 web_contents,
357 suggested_path,
358 can_save_as_complete,
359 callback);
360 #else
361 new SavePackageFilePicker(
362 web_contents,
363 suggested_path,
364 default_extension,
365 can_save_as_complete,
366 download_prefs_.get(),
367 callback);
368 #endif
371 void ChromeDownloadManagerDelegate::OpenDownload(DownloadItem* download) {
372 DCHECK(download->IsComplete());
373 if (!download->CanOpenDownload())
374 return;
375 platform_util::OpenItem(GetPlatformDownloadPath(profile_, download));
378 void ChromeDownloadManagerDelegate::ShowDownloadInShell(
379 DownloadItem* download) {
380 if (!download->CanShowInFolder())
381 return;
382 platform_util::ShowItemInFolder(GetPlatformDownloadPath(profile_, download));
385 void ChromeDownloadManagerDelegate::CheckForFileExistence(
386 DownloadItem* download,
387 const content::CheckForFileExistenceCallback& callback) {
388 #if defined(OS_CHROMEOS)
389 drive::DownloadHandler* drive_download_handler =
390 drive::DownloadHandler::GetForProfile(profile_);
391 if (drive_download_handler &&
392 drive_download_handler->IsDriveDownload(download)) {
393 drive_download_handler->CheckForFileExistence(download, callback);
394 return;
396 #endif
397 BrowserThread::PostTaskAndReplyWithResult(
398 BrowserThread::FILE, FROM_HERE,
399 base::Bind(&file_util::PathExists, download->GetTargetFilePath()),
400 callback);
403 void ChromeDownloadManagerDelegate::ClearLastDownloadPath() {
404 last_download_path_.clear();
407 DownloadProtectionService*
408 ChromeDownloadManagerDelegate::GetDownloadProtectionService() {
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
410 #if defined(FULL_SAFE_BROWSING)
411 SafeBrowsingService* sb_service = g_browser_process->safe_browsing_service();
412 if (sb_service && sb_service->download_protection_service() &&
413 profile_->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) {
414 return sb_service->download_protection_service();
416 #endif
417 return NULL;
420 void ChromeDownloadManagerDelegate::NotifyExtensions(
421 DownloadItem* download,
422 const base::FilePath& virtual_path,
423 const NotifyExtensionsCallback& callback) {
424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
425 #if !defined(OS_ANDROID)
426 ExtensionDownloadsEventRouter* router =
427 DownloadServiceFactory::GetForProfile(profile_)->
428 GetExtensionEventRouter();
429 if (router) {
430 base::Closure original_path_callback =
431 base::Bind(callback, base::FilePath(),
432 DownloadPathReservationTracker::UNIQUIFY);
433 router->OnDeterminingFilename(download, virtual_path.BaseName(),
434 original_path_callback,
435 callback);
436 return;
438 #endif
439 callback.Run(base::FilePath(), DownloadPathReservationTracker::UNIQUIFY);
442 void ChromeDownloadManagerDelegate::ReserveVirtualPath(
443 content::DownloadItem* download,
444 const base::FilePath& virtual_path,
445 bool create_directory,
446 DownloadPathReservationTracker::FilenameConflictAction conflict_action,
447 const DownloadTargetDeterminerDelegate::ReservedPathCallback& callback) {
448 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
449 DCHECK(!virtual_path.empty());
450 #if defined(OS_CHROMEOS)
451 // TODO(asanka): Handle path reservations for virtual paths as well.
452 // http://crbug.com/151618
453 if (drive::util::IsUnderDriveMountPoint(virtual_path)) {
454 callback.Run(virtual_path, true);
455 return;
457 #endif
458 DownloadPathReservationTracker::GetReservedPath(
459 *download, virtual_path, download_prefs_->DownloadPath(),
460 create_directory, conflict_action, callback);
463 void ChromeDownloadManagerDelegate::PromptUserForDownloadPath(
464 DownloadItem* download,
465 const base::FilePath& suggested_path,
466 const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback) {
467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
468 DownloadFilePicker::ShowFilePicker(
469 download,
470 suggested_path,
471 base::Bind(&ChromeDownloadManagerDelegate::OnDownloadPathSelected,
472 this,
473 callback));
476 void ChromeDownloadManagerDelegate::OnDownloadPathSelected(
477 const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback,
478 const base::FilePath& virtual_path) {
479 if (!virtual_path.empty())
480 last_download_path_ = virtual_path.DirName();
481 callback.Run(virtual_path);
484 void ChromeDownloadManagerDelegate::DetermineLocalPath(
485 DownloadItem* download,
486 const base::FilePath& virtual_path,
487 const DownloadTargetDeterminerDelegate::LocalPathCallback& callback) {
488 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
489 #if defined(OS_CHROMEOS)
490 drive::DownloadHandler* drive_download_handler =
491 drive::DownloadHandler::GetForProfile(profile_);
492 if (drive_download_handler) {
493 drive_download_handler->SubstituteDriveDownloadPath(
494 virtual_path, download, callback);
495 return;
497 #endif
498 callback.Run(virtual_path);
501 void ChromeDownloadManagerDelegate::CheckDownloadUrl(
502 DownloadItem* download,
503 const base::FilePath& suggested_path,
504 const CheckDownloadUrlCallback& callback) {
505 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
507 #if defined(FULL_SAFE_BROWSING)
508 safe_browsing::DownloadProtectionService* service =
509 GetDownloadProtectionService();
510 if (service) {
511 bool is_content_check_supported =
512 service->IsSupportedDownload(*download, suggested_path);
513 VLOG(2) << __FUNCTION__ << "() Start SB URL check for download = "
514 << download->DebugString(false);
515 service->CheckDownloadUrl(*download,
516 base::Bind(&CheckDownloadUrlDone,
517 callback,
518 is_content_check_supported));
519 return;
521 #endif
522 callback.Run(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
525 void ChromeDownloadManagerDelegate::CheckClientDownloadDone(
526 int32 download_id,
527 DownloadProtectionService::DownloadCheckResult result) {
528 DownloadItem* item = download_manager_->GetDownload(download_id);
529 if (!item || (item->GetState() != DownloadItem::IN_PROGRESS))
530 return;
532 VLOG(2) << __FUNCTION__ << "() download = " << item->DebugString(false)
533 << " verdict = " << result;
534 // We only mark the content as being dangerous if the download's safety state
535 // has not been set to DANGEROUS yet. We don't want to show two warnings.
536 if (item->GetDangerType() == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
537 item->GetDangerType() ==
538 content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT) {
539 switch (result) {
540 case DownloadProtectionService::SAFE:
541 // Do nothing.
542 break;
543 case DownloadProtectionService::DANGEROUS:
544 item->OnContentCheckCompleted(
545 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT);
546 break;
547 case DownloadProtectionService::UNCOMMON:
548 item->OnContentCheckCompleted(
549 content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT);
550 break;
551 case DownloadProtectionService::DANGEROUS_HOST:
552 item->OnContentCheckCompleted(
553 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST);
554 break;
558 SafeBrowsingState* state = static_cast<SafeBrowsingState*>(
559 item->GetUserData(&safe_browsing_id));
560 state->SetVerdict(result);
563 // content::NotificationObserver implementation.
564 void ChromeDownloadManagerDelegate::Observe(
565 int type,
566 const content::NotificationSource& source,
567 const content::NotificationDetails& details) {
568 DCHECK(type == chrome::NOTIFICATION_CRX_INSTALLER_DONE);
570 registrar_.Remove(this,
571 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
572 source);
574 scoped_refptr<extensions::CrxInstaller> installer =
575 content::Source<extensions::CrxInstaller>(source).ptr();
576 content::DownloadOpenDelayedCallback callback = crx_installers_[installer];
577 crx_installers_.erase(installer.get());
578 callback.Run(installer->did_handle_successfully());