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