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 31namespace content { 32 33ShellDownloadManagerDelegate::ShellDownloadManagerDelegate() 34 : download_manager_(NULL), 35 suppress_prompting_(false), 36 weak_ptr_factory_(this) {} 37 38ShellDownloadManagerDelegate::~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 48void ShellDownloadManagerDelegate::SetDownloadManager( 49 DownloadManager* download_manager) { 50 download_manager_ = download_manager; 51} 52 53void 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 60bool 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 98bool 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 110void ShellDownloadManagerDelegate::GetNextId( 111 const DownloadIdCallback& callback) { 112 static uint32 next_id = DownloadItem::kInvalidId + 1; 113 callback.Run(next_id++); 114} 115 116// static 117void 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 140void 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 156void 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 196void 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