blob: 78dec2a890dda4f644593b24654188f651f18baf [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2013 The Chromium Authors
[email protected]98d6f152011-09-29 19:35:512// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]de7d61ff2013-08-20 11:30:415#include "content/shell/browser/shell_download_manager_delegate.h"
[email protected]98d6f152011-09-29 19:35:516
Ho Cheung8a5929d2023-04-26 17:46:477#include <algorithm>
David Vallet11683522017-08-23 03:20:468#include <string>
9
Wenbo Jie0bc233c2024-04-09 04:26:1510#include "base/files/file_path.h"
Daniel Cheng4f1c5332025-06-19 19:37:2111#include "base/notimplemented.h"
Xiaohan Wangbd084422022-01-15 18:47:5112#include "build/build_config.h"
Avi Drissman62a617a2024-01-19 22:37:1213#include "components/download/public/common/download_target_info.h"
Xiaohan Wangbd084422022-01-15 18:47:5114
15#if BUILDFLAG(IS_WIN)
[email protected]5c12f4a2011-09-30 21:59:0416#include <windows.h>
Takuto Ikutac8d6b16f2024-04-15 16:59:1917
[email protected]5c12f4a2011-09-30 21:59:0418#include <commdlg.h>
19#endif
20
Hans Wennborg0917de892020-04-28 20:21:1521#include "base/check_op.h"
[email protected]e6669302013-03-25 14:31:1622#include "base/command_line.h"
Tom Sepez315bfe82025-03-24 18:00:3023#include "base/compiler_specific.h"
thestigb7aad54f2014-09-05 18:25:3924#include "base/files/file_util.h"
Avi Drissmanadac21992023-01-11 23:46:3925#include "base/functional/bind.h"
Hans Wennborg0917de892020-04-28 20:21:1526#include "base/notreached.h"
[email protected]21aa99682013-06-11 07:17:0127#include "base/strings/string_util.h"
[email protected]74ebfb12013-06-07 20:48:0028#include "base/strings/utf_string_conversions.h"
Gabriel Charette5e2e72042020-02-25 01:04:0129#include "base/task/thread_pool.h"
[email protected]ccb797302011-12-15 16:55:1130#include "content/public/browser/browser_context.h"
Eric Seckler8652dcd52018-09-20 10:42:2831#include "content/public/browser/browser_task_traits.h"
[email protected]c38831a12011-10-28 12:44:4932#include "content/public/browser/browser_thread.h"
Min Qina9f487872018-02-09 20:43:2333#include "content/public/browser/download_item_utils.h"
[email protected]e582fdd2011-12-20 16:48:1734#include "content/public/browser/download_manager.h"
[email protected]0b659b32012-03-26 21:29:3235#include "content/public/browser/web_contents.h"
[email protected]b7c504c2013-05-07 14:42:1236#include "content/shell/common/shell_switches.h"
[email protected]d96cf752014-04-09 04:05:2837#include "net/base/filename_util.h"
[email protected]98d6f152011-09-29 19:35:5138
Xiaohan Wangbd084422022-01-15 18:47:5139#if BUILDFLAG(IS_WIN)
[email protected]517fce722014-01-15 05:16:1440#include "ui/aura/window.h"
[email protected]7a60cd3a2014-03-20 20:54:5741#include "ui/aura/window_tree_host.h"
[email protected]517fce722014-01-15 05:16:1442#endif
43
[email protected]98d6f152011-09-29 19:35:5144namespace content {
45
46ShellDownloadManagerDelegate::ShellDownloadManagerDelegate()
Jeremy Roman3bca4bf2019-07-11 03:41:2547 : download_manager_(nullptr), suppress_prompting_(false) {}
[email protected]98d6f152011-09-29 19:35:5148
Asanka Herath1ba0e9f2017-04-03 18:48:5349ShellDownloadManagerDelegate::~ShellDownloadManagerDelegate() {
[email protected]7cef82172013-12-17 06:58:3750 if (download_manager_) {
Ivan Kotenkov2c0d2bb32017-11-01 15:41:2851 download_manager_->SetDelegate(nullptr);
52 download_manager_ = nullptr;
[email protected]7cef82172013-12-17 06:58:3753 }
[email protected]98d6f152011-09-29 19:35:5154}
55
56
57void ShellDownloadManagerDelegate::SetDownloadManager(
58 DownloadManager* download_manager) {
59 download_manager_ = download_manager;
60}
61
[email protected]854e1312012-07-30 17:26:3062void ShellDownloadManagerDelegate::Shutdown() {
[email protected]7cef82172013-12-17 06:58:3763 // Revoke any pending callbacks. download_manager_ et. al. are no longer safe
64 // to access after this point.
65 weak_ptr_factory_.InvalidateWeakPtrs();
Ivan Kotenkov2c0d2bb32017-11-01 15:41:2866 download_manager_ = nullptr;
[email protected]854e1312012-07-30 17:26:3067}
68
[email protected]47665442012-07-27 02:31:2269bool ShellDownloadManagerDelegate::DetermineDownloadTarget(
Min Qina9f487872018-02-09 20:43:2370 download::DownloadItem* download,
Avi Drissman62a617a2024-01-19 22:37:1271 download::DownloadTargetCallback* callback) {
mostynb4e363892015-03-23 14:35:0572 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]a558b43a2012-08-30 17:09:2773 // This assignment needs to be here because even at the call to
74 // SetDownloadManager, the system is not fully initialized.
75 if (default_download_path_.empty()) {
Wenbo Jie0bc233c2024-04-09 04:26:1576 default_download_path_ = download_manager_->GetBrowserContext()
77 ->GetPath()
78#if BUILDFLAG(IS_CHROMEOS)
79 .Append(FILE_PATH_LITERAL("MyFiles"))
80#endif
81 .Append(FILE_PATH_LITERAL("Downloads"));
[email protected]a558b43a2012-08-30 17:09:2782 }
83
[email protected]3d833de2012-05-30 23:32:0684 if (!download->GetForcedFilePath().empty()) {
Avi Drissman62a617a2024-01-19 22:37:1285 download::DownloadTargetInfo target_info;
86 target_info.target_path = download->GetForcedFilePath();
87 target_info.intermediate_path = download->GetForcedFilePath();
88
89 std::move(*callback).Run(std::move(target_info));
[email protected]98d6f152011-09-29 19:35:5190 return true;
[email protected]3d833de2012-05-30 23:32:0691 }
[email protected]98d6f152011-09-29 19:35:5192
danakja9fe91c2019-05-01 19:02:2993 FilenameDeterminedCallback filename_determined_callback = base::BindOnce(
94 &ShellDownloadManagerDelegate::OnDownloadPathGenerated,
danakja3cfb8332019-12-10 21:13:3395 weak_ptr_factory_.GetWeakPtr(), download->GetId(), std::move(*callback));
[email protected]98d6f152011-09-29 19:35:5196
Gabriel Charette5e2e72042020-02-25 01:04:0197 base::ThreadPool::PostTask(
98 FROM_HERE,
99 {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
100 base::TaskPriority::USER_VISIBLE},
101 base::BindOnce(&ShellDownloadManagerDelegate::GenerateFilename,
102 download->GetURL(), download->GetContentDisposition(),
103 download->GetSuggestedFilename(), download->GetMimeType(),
104 default_download_path_,
105 std::move(filename_determined_callback)));
[email protected]a558b43a2012-08-30 17:09:27106 return true;
[email protected]98d6f152011-09-29 19:35:51107}
108
[email protected]e6669302013-03-25 14:31:16109bool ShellDownloadManagerDelegate::ShouldOpenDownload(
Min Qina9f487872018-02-09 20:43:23110 download::DownloadItem* item,
danakj8c70a442019-12-10 22:48:24111 DownloadOpenDelayedCallback callback) {
[email protected]e6669302013-03-25 14:31:16112 return true;
113}
114
danakja6dd6f52019-12-10 19:04:52115void ShellDownloadManagerDelegate::GetNextId(DownloadIdCallback callback) {
Min Qina9f487872018-02-09 20:43:23116 static uint32_t next_id = download::DownloadItem::kInvalidId + 1;
danakja6dd6f52019-12-10 19:04:52117 std::move(callback).Run(next_id++);
[email protected]530047e2013-07-12 17:02:25118}
119
[email protected]7cef82172013-12-17 06:58:37120// static
[email protected]98d6f152011-09-29 19:35:51121void ShellDownloadManagerDelegate::GenerateFilename(
[email protected]7cef82172013-12-17 06:58:37122 const GURL& url,
123 const std::string& content_disposition,
124 const std::string& suggested_filename,
125 const std::string& mime_type,
126 const base::FilePath& suggested_directory,
danakja9fe91c2019-05-01 19:02:29127 FilenameDeterminedCallback callback) {
[email protected]7cef82172013-12-17 06:58:37128 base::FilePath generated_name = net::GenerateFileName(url,
129 content_disposition,
130 std::string(),
131 suggested_filename,
132 mime_type,
133 "download");
134
[email protected]7567484142013-07-11 17:36:07135 if (!base::PathExists(suggested_directory))
[email protected]426d1c92013-12-03 20:08:54136 base::CreateDirectory(suggested_directory);
[email protected]98d6f152011-09-29 19:35:51137
[email protected]d30a36f2013-02-07 04:16:26138 base::FilePath suggested_path(suggested_directory.Append(generated_name));
Gabriel Charettee7cdc5cd2020-05-27 23:35:05139 GetUIThreadTaskRunner({})->PostTask(
140 FROM_HERE, base::BindOnce(std::move(callback), suggested_path));
[email protected]98d6f152011-09-29 19:35:51141}
142
[email protected]a558b43a2012-08-30 17:09:27143void ShellDownloadManagerDelegate::OnDownloadPathGenerated(
avi66a07722015-12-25 23:38:12144 uint32_t download_id,
Avi Drissman62a617a2024-01-19 22:37:12145 download::DownloadTargetCallback callback,
[email protected]d30a36f2013-02-07 04:16:26146 const base::FilePath& suggested_path) {
mostynb4e363892015-03-23 14:35:05147 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]a558b43a2012-08-30 17:09:27148 if (suppress_prompting_) {
149 // Testing exit.
Avi Drissman62a617a2024-01-19 22:37:12150 download::DownloadTargetInfo target_info;
151 target_info.target_path = suggested_path;
152 target_info.intermediate_path =
153 suggested_path.AddExtension(FILE_PATH_LITERAL(".crdownload"));
154
155 std::move(callback).Run(std::move(target_info));
[email protected]a558b43a2012-08-30 17:09:27156 return;
157 }
158
danakja3cfb8332019-12-10 21:13:33159 ChooseDownloadPath(download_id, std::move(callback), suggested_path);
[email protected]a558b43a2012-08-30 17:09:27160}
161
[email protected]47665442012-07-27 02:31:22162void ShellDownloadManagerDelegate::ChooseDownloadPath(
avi66a07722015-12-25 23:38:12163 uint32_t download_id,
Avi Drissman62a617a2024-01-19 22:37:12164 download::DownloadTargetCallback callback,
[email protected]d30a36f2013-02-07 04:16:26165 const base::FilePath& suggested_path) {
mostynb4e363892015-03-23 14:35:05166 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Min Qina9f487872018-02-09 20:43:23167 download::DownloadItem* item = download_manager_->GetDownload(download_id);
168 if (!item || (item->GetState() != download::DownloadItem::IN_PROGRESS))
[email protected]98d6f152011-09-29 19:35:51169 return;
[email protected]3d833de2012-05-30 23:32:06170
[email protected]d30a36f2013-02-07 04:16:26171 base::FilePath result;
Xiaohan Wangbd084422022-01-15 18:47:51172#if BUILDFLAG(IS_WIN)
[email protected]d30a36f2013-02-07 04:16:26173 std::wstring file_part = base::FilePath(suggested_path).BaseName().value();
[email protected]5c12f4a2011-09-30 21:59:04174 wchar_t file_name[MAX_PATH];
Tom Sepez315bfe82025-03-24 18:00:30175 UNSAFE_TODO(
176 base::wcslcpy(file_name, file_part.c_str(), std::size(file_name)));
[email protected]5c12f4a2011-09-30 21:59:04177 OPENFILENAME save_as;
Tom Sepez315bfe82025-03-24 18:00:30178 UNSAFE_TODO(ZeroMemory(&save_as, sizeof(save_as)));
[email protected]5c12f4a2011-09-30 21:59:04179 save_as.lStructSize = sizeof(OPENFILENAME);
Tsuyoshi Horoab90fd502019-11-13 19:18:59180 WebContents* web_contents = DownloadItemUtils::GetWebContents(item);
181 // |web_contents| could be null if the tab was quickly closed.
182 if (!web_contents)
183 return;
184 save_as.hwndOwner =
185 web_contents->GetNativeView()->GetHost()->GetAcceleratedWidget();
[email protected]5c12f4a2011-09-30 21:59:04186 save_as.lpstrFile = file_name;
Daniel Chengad44af2f2022-02-26 18:07:54187 save_as.nMaxFile = std::size(file_name);
[email protected]5c12f4a2011-09-30 21:59:04188
189 std::wstring directory;
190 if (!suggested_path.empty())
191 directory = suggested_path.DirName().value();
192
193 save_as.lpstrInitialDir = directory.c_str();
194 save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
195 OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
196
197 if (GetSaveFileName(&save_as))
[email protected]d30a36f2013-02-07 04:16:26198 result = base::FilePath(std::wstring(save_as.lpstrFile));
[email protected]5c12f4a2011-09-30 21:59:04199#else
200 NOTIMPLEMENTED();
201#endif
202
Avi Drissman62a617a2024-01-19 22:37:12203 download::DownloadTargetInfo target_info;
204 target_info.target_path = result;
205 target_info.intermediate_path = result;
206 target_info.target_disposition =
207 download::DownloadItem::TARGET_DISPOSITION_PROMPT;
208
209 std::move(callback).Run(std::move(target_info));
[email protected]98d6f152011-09-29 19:35:51210}
211
[email protected]a558b43a2012-08-30 17:09:27212void ShellDownloadManagerDelegate::SetDownloadBehaviorForTesting(
[email protected]d30a36f2013-02-07 04:16:26213 const base::FilePath& default_download_path) {
[email protected]a558b43a2012-08-30 17:09:27214 default_download_path_ = default_download_path;
215 suppress_prompting_ = true;
216}
217
[email protected]98d6f152011-09-29 19:35:51218} // namespace content