Home | History | Annotate | Download | only in browser
      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 "content/shell/browser/shell_download_manager_delegate.h"
      6 
      7 #if defined(OS_WIN)
      8 #include <windows.h>
      9 #include <commdlg.h>
     10 #endif
     11 
     12 #include "base/bind.h"
     13 #include "base/command_line.h"
     14 #include "base/files/file_util.h"
     15 #include "base/logging.h"
     16 #include "base/strings/string_util.h"
     17 #include "base/strings/utf_string_conversions.h"
     18 #include "content/public/browser/browser_context.h"
     19 #include "content/public/browser/browser_thread.h"
     20 #include "content/public/browser/download_manager.h"
     21 #include "content/public/browser/web_contents.h"
     22 #include "content/shell/browser/webkit_test_controller.h"
     23 #include "content/shell/common/shell_switches.h"
     24 #include "net/base/filename_util.h"
     25 
     26 #if defined(OS_WIN)
     27 #include "ui/aura/window.h"
     28 #include "ui/aura/window_tree_host.h"
     29 #endif
     30 
     31 namespace content {
     32 
     33 ShellDownloadManagerDelegate::ShellDownloadManagerDelegate()
     34     : download_manager_(NULL),
     35       suppress_prompting_(false),
     36       weak_ptr_factory_(this) {}
     37 
     38 ShellDownloadManagerDelegate::~ShellDownloadManagerDelegate(){
     39   if (download_manager_) {
     40     DCHECK_EQ(static_cast<DownloadManagerDelegate*>(this),
     41               download_manager_->GetDelegate());
     42     download_manager_->SetDelegate(NULL);
     43     download_manager_ = NULL;
     44   }
     45 }
     46 
     47 
     48 void ShellDownloadManagerDelegate::SetDownloadManager(
     49     DownloadManager* download_manager) {
     50   download_manager_ = download_manager;
     51 }
     52 
     53 void ShellDownloadManagerDelegate::Shutdown() {
     54   // Revoke any pending callbacks. download_manager_ et. al. are no longer safe
     55   // to access after this point.
     56   weak_ptr_factory_.InvalidateWeakPtrs();
     57   download_manager_ = NULL;
     58 }
     59 
     60 bool ShellDownloadManagerDelegate::DetermineDownloadTarget(
     61     DownloadItem* download,
     62     const DownloadTargetCallback& callback) {
     63   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     64   // This assignment needs to be here because even at the call to
     65   // SetDownloadManager, the system is not fully initialized.
     66   if (default_download_path_.empty()) {
     67     default_download_path_ = download_manager_->GetBrowserContext()->GetPath().
     68         Append(FILE_PATH_LITERAL("Downloads"));
     69   }
     70 
     71   if (!download->GetForcedFilePath().empty()) {
     72     callback.Run(download->GetForcedFilePath(),
     73                  DownloadItem::TARGET_DISPOSITION_OVERWRITE,
     74                  DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
     75                  download->GetForcedFilePath());
     76     return true;
     77   }
     78 
     79   FilenameDeterminedCallback filename_determined_callback =
     80       base::Bind(&ShellDownloadManagerDelegate::OnDownloadPathGenerated,
     81                  weak_ptr_factory_.GetWeakPtr(),
     82                  download->GetId(),
     83                  callback);
     84 
     85   BrowserThread::PostTask(
     86       BrowserThread::FILE,
     87       FROM_HERE,
     88       base::Bind(&ShellDownloadManagerDelegate::GenerateFilename,
     89                  download->GetURL(),
     90                  download->GetContentDisposition(),
     91                  download->GetSuggestedFilename(),
     92                  download->GetMimeType(),
     93                  default_download_path_,
     94                  filename_determined_callback));
     95   return true;
     96 }
     97 
     98 bool ShellDownloadManagerDelegate::ShouldOpenDownload(
     99       DownloadItem* item,
    100       const DownloadOpenDelayedCallback& callback) {
    101   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree) &&
    102       WebKitTestController::Get()->IsMainWindow(item->GetWebContents()) &&
    103       item->GetMimeType() == "text/html") {
    104     WebKitTestController::Get()->OpenURL(
    105         net::FilePathToFileURL(item->GetFullPath()));
    106   }
    107   return true;
    108 }
    109 
    110 void ShellDownloadManagerDelegate::GetNextId(
    111     const DownloadIdCallback& callback) {
    112   static uint32 next_id = DownloadItem::kInvalidId + 1;
    113   callback.Run(next_id++);
    114 }
    115 
    116 // static
    117 void ShellDownloadManagerDelegate::GenerateFilename(
    118     const GURL& url,
    119     const std::string& content_disposition,
    120     const std::string& suggested_filename,
    121     const std::string& mime_type,
    122     const base::FilePath& suggested_directory,
    123     const FilenameDeterminedCallback& callback) {
    124   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    125   base::FilePath generated_name = net::GenerateFileName(url,
    126                                                         content_disposition,
    127                                                         std::string(),
    128                                                         suggested_filename,
    129                                                         mime_type,
    130                                                         "download");
    131 
    132   if (!base::PathExists(suggested_directory))
    133     base::CreateDirectory(suggested_directory);
    134 
    135   base::FilePath suggested_path(suggested_directory.Append(generated_name));
    136   BrowserThread::PostTask(
    137       BrowserThread::UI, FROM_HERE, base::Bind(callback, suggested_path));
    138 }
    139 
    140 void ShellDownloadManagerDelegate::OnDownloadPathGenerated(
    141     uint32 download_id,
    142     const DownloadTargetCallback& callback,
    143     const base::FilePath& suggested_path) {
    144   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    145   if (suppress_prompting_) {
    146     // Testing exit.
    147     callback.Run(suggested_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    148                  DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
    149                  suggested_path.AddExtension(FILE_PATH_LITERAL(".crdownload")));
    150     return;
    151   }
    152 
    153   ChooseDownloadPath(download_id, callback, suggested_path);
    154 }
    155 
    156 void ShellDownloadManagerDelegate::ChooseDownloadPath(
    157     uint32 download_id,
    158     const DownloadTargetCallback& callback,
    159     const base::FilePath& suggested_path) {
    160   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    161   DownloadItem* item = download_manager_->GetDownload(download_id);
    162   if (!item || (item->GetState() != DownloadItem::IN_PROGRESS))
    163     return;
    164 
    165   base::FilePath result;
    166 #if defined(OS_WIN)
    167   std::wstring file_part = base::FilePath(suggested_path).BaseName().value();
    168   wchar_t file_name[MAX_PATH];
    169   base::wcslcpy(file_name, file_part.c_str(), arraysize(file_name));
    170   OPENFILENAME save_as;
    171   ZeroMemory(&save_as, sizeof(save_as));
    172   save_as.lStructSize = sizeof(OPENFILENAME);
    173   save_as.hwndOwner = item->GetWebContents()->GetNativeView()->
    174       GetHost()->GetAcceleratedWidget();
    175   save_as.lpstrFile = file_name;
    176   save_as.nMaxFile = arraysize(file_name);
    177 
    178   std::wstring directory;
    179   if (!suggested_path.empty())
    180     directory = suggested_path.DirName().value();
    181 
    182   save_as.lpstrInitialDir = directory.c_str();
    183   save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
    184                   OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
    185 
    186   if (GetSaveFileName(&save_as))
    187     result = base::FilePath(std::wstring(save_as.lpstrFile));
    188 #else
    189   NOTIMPLEMENTED();
    190 #endif
    191 
    192   callback.Run(result, DownloadItem::TARGET_DISPOSITION_PROMPT,
    193                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, result);
    194 }
    195 
    196 void ShellDownloadManagerDelegate::SetDownloadBehaviorForTesting(
    197     const base::FilePath& default_download_path) {
    198   default_download_path_ = default_download_path;
    199   suppress_prompting_ = true;
    200 }
    201 
    202 }  // namespace content
    203