1 // Copyright 2018 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 "components/download/public/common/in_progress_download_manager.h"
6
7 #include "base/bind.h"
8 #include "base/optional.h"
9 #include "base/task/post_task.h"
10 #include "base/threading/thread_task_runner_handle.h"
11 #include "build/build_config.h"
12 #include "components/download/database/download_db_entry.h"
13 #include "components/download/database/download_db_impl.h"
14 #include "components/download/database/download_namespace.h"
15 #include "components/download/internal/common/download_db_cache.h"
16 #include "components/download/internal/common/resource_downloader.h"
17 #include "components/download/public/common/download_features.h"
18 #include "components/download/public/common/download_file.h"
19 #include "components/download/public/common/download_item_impl.h"
20 #include "components/download/public/common/download_start_observer.h"
21 #include "components/download/public/common/download_stats.h"
22 #include "components/download/public/common/download_task_runner.h"
23 #include "components/download/public/common/download_url_parameters.h"
24 #include "components/download/public/common/download_utils.h"
25 #include "components/download/public/common/input_stream.h"
26 #include "components/leveldb_proto/public/proto_database_provider.h"
27 #include "mojo/public/cpp/bindings/pending_remote.h"
28 #include "services/device/public/mojom/wake_lock_provider.mojom.h"
29 #include "services/network/public/cpp/resource_request.h"
30 #include "services/network/public/mojom/url_response_head.mojom.h"
31
32 #if defined(OS_ANDROID)
33 #include "components/download/internal/common/android/download_collection_bridge.h"
34 #include "components/download/public/common/download_path_reservation_tracker.h"
35 #endif
36
37 namespace download {
38
39 namespace {
40
CreateDownloadItemImpl(DownloadItemImplDelegate * delegate,const DownloadDBEntry entry,std::unique_ptr<DownloadEntry> download_entry)41 std::unique_ptr<DownloadItemImpl> CreateDownloadItemImpl(
42 DownloadItemImplDelegate* delegate,
43 const DownloadDBEntry entry,
44 std::unique_ptr<DownloadEntry> download_entry) {
45 if (!entry.download_info)
46 return nullptr;
47
48 // DownloadDBEntry migrated from in-progress cache has negative Ids.
49 if (entry.download_info->id < 0)
50 return nullptr;
51
52 base::Optional<InProgressInfo> in_progress_info =
53 entry.download_info->in_progress_info;
54 if (!in_progress_info)
55 return nullptr;
56 return std::make_unique<DownloadItemImpl>(
57 delegate, entry.download_info->guid, entry.download_info->id,
58 in_progress_info->current_path, in_progress_info->target_path,
59 in_progress_info->url_chain, in_progress_info->referrer_url,
60 in_progress_info->site_url, in_progress_info->tab_url,
61 in_progress_info->tab_referrer_url, base::nullopt,
62 in_progress_info->mime_type, in_progress_info->original_mime_type,
63 in_progress_info->start_time, in_progress_info->end_time,
64 in_progress_info->etag, in_progress_info->last_modified,
65 in_progress_info->received_bytes, in_progress_info->total_bytes,
66 in_progress_info->auto_resume_count, in_progress_info->hash,
67 in_progress_info->state, in_progress_info->danger_type,
68 in_progress_info->interrupt_reason, in_progress_info->paused,
69 in_progress_info->metered, false, base::Time(),
70 in_progress_info->transient, in_progress_info->received_slices,
71 std::move(download_entry));
72 }
73
OnUrlDownloadHandlerCreated(UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader,base::WeakPtr<InProgressDownloadManager> download_manager,const scoped_refptr<base::SingleThreadTaskRunner> & main_task_runner)74 void OnUrlDownloadHandlerCreated(
75 UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader,
76 base::WeakPtr<InProgressDownloadManager> download_manager,
77 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) {
78 main_task_runner->PostTask(
79 FROM_HERE,
80 base::BindOnce(&UrlDownloadHandler::Delegate::OnUrlDownloadHandlerCreated,
81 download_manager, std::move(downloader)));
82 }
83
BeginResourceDownload(std::unique_ptr<DownloadUrlParameters> params,std::unique_ptr<network::ResourceRequest> request,std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_url_loader_factory,const URLSecurityPolicy & url_security_policy,bool is_new_download,base::WeakPtr<InProgressDownloadManager> download_manager,const GURL & site_url,const GURL & tab_url,const GURL & tab_referrer_url,mojo::PendingRemote<device::mojom::WakeLockProvider> wake_lock_provider,bool is_background_mode,const scoped_refptr<base::SingleThreadTaskRunner> & main_task_runner)84 void BeginResourceDownload(
85 std::unique_ptr<DownloadUrlParameters> params,
86 std::unique_ptr<network::ResourceRequest> request,
87 std::unique_ptr<network::PendingSharedURLLoaderFactory>
88 pending_url_loader_factory,
89 const URLSecurityPolicy& url_security_policy,
90 bool is_new_download,
91 base::WeakPtr<InProgressDownloadManager> download_manager,
92 const GURL& site_url,
93 const GURL& tab_url,
94 const GURL& tab_referrer_url,
95 mojo::PendingRemote<device::mojom::WakeLockProvider> wake_lock_provider,
96 bool is_background_mode,
97 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) {
98 DCHECK(GetIOTaskRunner()->BelongsToCurrentThread());
99 UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader(
100 ResourceDownloader::BeginDownload(
101 download_manager, std::move(params), std::move(request),
102 network::SharedURLLoaderFactory::Create(
103 std::move(pending_url_loader_factory)),
104 url_security_policy, site_url, tab_url, tab_referrer_url,
105 is_new_download, false, std::move(wake_lock_provider),
106 is_background_mode, main_task_runner)
107 .release(),
108 base::OnTaskRunnerDeleter(base::ThreadTaskRunnerHandle::Get()));
109
110 OnUrlDownloadHandlerCreated(std::move(downloader), download_manager,
111 main_task_runner);
112 }
113
CreateDownloadHandlerForNavigation(base::WeakPtr<InProgressDownloadManager> download_manager,std::unique_ptr<network::ResourceRequest> resource_request,int render_process_id,int render_frame_id,const GURL & site_url,const GURL & tab_url,const GURL & tab_referrer_url,std::vector<GURL> url_chain,net::CertStatus cert_status,network::mojom::URLResponseHeadPtr response_head,mojo::ScopedDataPipeConsumerHandle response_body,network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_url_loader_factory,const URLSecurityPolicy & url_security_policy,mojo::PendingRemote<device::mojom::WakeLockProvider> wake_lock_provider,const scoped_refptr<base::SingleThreadTaskRunner> & main_task_runner)114 void CreateDownloadHandlerForNavigation(
115 base::WeakPtr<InProgressDownloadManager> download_manager,
116 std::unique_ptr<network::ResourceRequest> resource_request,
117 int render_process_id,
118 int render_frame_id,
119 const GURL& site_url,
120 const GURL& tab_url,
121 const GURL& tab_referrer_url,
122 std::vector<GURL> url_chain,
123 net::CertStatus cert_status,
124 network::mojom::URLResponseHeadPtr response_head,
125 mojo::ScopedDataPipeConsumerHandle response_body,
126 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
127 std::unique_ptr<network::PendingSharedURLLoaderFactory>
128 pending_url_loader_factory,
129 const URLSecurityPolicy& url_security_policy,
130 mojo::PendingRemote<device::mojom::WakeLockProvider> wake_lock_provider,
131 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) {
132 DCHECK(GetIOTaskRunner()->BelongsToCurrentThread());
133
134 ResourceDownloader::InterceptNavigationResponse(
135 download_manager, std::move(resource_request), render_process_id,
136 render_frame_id, site_url, tab_url, tab_referrer_url,
137 std::move(url_chain), std::move(cert_status), std::move(response_head),
138 std::move(response_body), std::move(url_loader_client_endpoints),
139 network::SharedURLLoaderFactory::Create(
140 std::move(pending_url_loader_factory)),
141 url_security_policy, std::move(wake_lock_provider), main_task_runner);
142 }
143
144 #if defined(OS_ANDROID)
OnDownloadDisplayNamesReturned(DownloadCollectionBridge::GetDisplayNamesCallback callback,const scoped_refptr<base::SingleThreadTaskRunner> & main_task_runner,InProgressDownloadManager::DisplayNames download_names)145 void OnDownloadDisplayNamesReturned(
146 DownloadCollectionBridge::GetDisplayNamesCallback callback,
147 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
148 InProgressDownloadManager::DisplayNames download_names) {
149 main_task_runner->PostTask(
150 FROM_HERE,
151 base::BindOnce(std::move(callback), std::move(download_names)));
152 }
153
OnPathReserved(DownloadItemImplDelegate::DownloadTargetCallback callback,DownloadDangerType danger_type,DownloadItem::MixedContentStatus mixed_content_status,const InProgressDownloadManager::IntermediatePathCallback & intermediate_path_cb,const base::FilePath & forced_file_path,PathValidationResult result,const base::FilePath & target_path)154 void OnPathReserved(DownloadItemImplDelegate::DownloadTargetCallback callback,
155 DownloadDangerType danger_type,
156 DownloadItem::MixedContentStatus mixed_content_status,
157 const InProgressDownloadManager::IntermediatePathCallback&
158 intermediate_path_cb,
159 const base::FilePath& forced_file_path,
160 PathValidationResult result,
161 const base::FilePath& target_path) {
162 base::FilePath intermediate_path;
163 if (!target_path.empty() &&
164 (result == PathValidationResult::SUCCESS ||
165 result == download::PathValidationResult::SAME_AS_SOURCE)) {
166 if (!forced_file_path.empty()) {
167 DCHECK_EQ(target_path, forced_file_path);
168 intermediate_path = target_path;
169 } else if (intermediate_path_cb) {
170 intermediate_path = intermediate_path_cb.Run(target_path);
171 }
172 }
173
174 RecordBackgroundTargetDeterminationResult(
175 intermediate_path.empty()
176 ? BackgroudTargetDeterminationResultTypes::kPathReservationFailed
177 : BackgroudTargetDeterminationResultTypes::kSuccess);
178 std::move(callback).Run(
179 target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE, danger_type,
180 mixed_content_status, intermediate_path,
181 intermediate_path.empty() ? DOWNLOAD_INTERRUPT_REASON_FILE_FAILED
182 : DOWNLOAD_INTERRUPT_REASON_NONE);
183 }
184 #endif
185
186 } // namespace
187
InterceptDownload(const DownloadCreateInfo & download_create_info)188 bool InProgressDownloadManager::Delegate::InterceptDownload(
189 const DownloadCreateInfo& download_create_info) {
190 return false;
191 }
192
193 base::FilePath
GetDefaultDownloadDirectory()194 InProgressDownloadManager::Delegate::GetDefaultDownloadDirectory() {
195 return base::FilePath();
196 }
197
InProgressDownloadManager(Delegate * delegate,const base::FilePath & in_progress_db_dir,leveldb_proto::ProtoDatabaseProvider * db_provider,const IsOriginSecureCallback & is_origin_secure_cb,const URLSecurityPolicy & url_security_policy,WakeLockProviderBinder wake_lock_provider_binder)198 InProgressDownloadManager::InProgressDownloadManager(
199 Delegate* delegate,
200 const base::FilePath& in_progress_db_dir,
201 leveldb_proto::ProtoDatabaseProvider* db_provider,
202 const IsOriginSecureCallback& is_origin_secure_cb,
203 const URLSecurityPolicy& url_security_policy,
204 WakeLockProviderBinder wake_lock_provider_binder)
205 : delegate_(delegate),
206 file_factory_(new DownloadFileFactory()),
207 download_start_observer_(nullptr),
208 is_origin_secure_cb_(is_origin_secure_cb),
209 url_security_policy_(url_security_policy),
210 wake_lock_provider_binder_(std::move(wake_lock_provider_binder)) {
211 Initialize(in_progress_db_dir, db_provider);
212 }
213
214 InProgressDownloadManager::~InProgressDownloadManager() = default;
215
OnUrlDownloadStarted(std::unique_ptr<DownloadCreateInfo> download_create_info,std::unique_ptr<InputStream> input_stream,URLLoaderFactoryProvider::URLLoaderFactoryProviderPtr url_loader_factory_provider,UrlDownloadHandler * downloader,DownloadUrlParameters::OnStartedCallback callback)216 void InProgressDownloadManager::OnUrlDownloadStarted(
217 std::unique_ptr<DownloadCreateInfo> download_create_info,
218 std::unique_ptr<InputStream> input_stream,
219 URLLoaderFactoryProvider::URLLoaderFactoryProviderPtr
220 url_loader_factory_provider,
221 UrlDownloadHandler* downloader,
222 DownloadUrlParameters::OnStartedCallback callback) {
223 // If a new download's GUID already exists, skip it.
224 if (!download_create_info->guid.empty() &&
225 download_create_info->is_new_download &&
226 GetDownloadByGuid(download_create_info->guid)) {
227 LOG(WARNING) << "A download with the same GUID already exists, the new "
228 "request is ignored.";
229 return;
230 }
231 StartDownload(std::move(download_create_info), std::move(input_stream),
232 std::move(url_loader_factory_provider),
233 base::BindOnce(&InProgressDownloadManager::CancelUrlDownload,
234 weak_factory_.GetWeakPtr(), downloader),
235 std::move(callback));
236 }
237
OnUrlDownloadStopped(UrlDownloadHandler * downloader)238 void InProgressDownloadManager::OnUrlDownloadStopped(
239 UrlDownloadHandler* downloader) {
240 for (auto ptr = url_download_handlers_.begin();
241 ptr != url_download_handlers_.end(); ++ptr) {
242 if (ptr->get() == downloader) {
243 url_download_handlers_.erase(ptr);
244 return;
245 }
246 }
247 }
248
OnUrlDownloadHandlerCreated(UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader)249 void InProgressDownloadManager::OnUrlDownloadHandlerCreated(
250 UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader) {
251 if (downloader)
252 url_download_handlers_.push_back(std::move(downloader));
253 }
254
DownloadUrl(std::unique_ptr<DownloadUrlParameters> params)255 void InProgressDownloadManager::DownloadUrl(
256 std::unique_ptr<DownloadUrlParameters> params) {
257 if (!CanDownload(params.get()))
258 return;
259
260 // Start the new download, the download should be saved to the file path
261 // specifcied in the |params|.
262 BeginDownload(std::move(params), url_loader_factory_->Clone(),
263 true /* is_new_download */, GURL() /* site_url */,
264 GURL() /* tab_url */, GURL() /* tab_referral_url */);
265 }
266
CanDownload(DownloadUrlParameters * params)267 bool InProgressDownloadManager::CanDownload(DownloadUrlParameters* params) {
268 if (!params->is_transient())
269 return false;
270
271 if (!url_loader_factory_)
272 return false;
273
274 if (params->require_safety_checks())
275 return false;
276
277 if (params->file_path().empty())
278 return false;
279
280 return true;
281 }
282
GetAllDownloads(SimpleDownloadManager::DownloadVector * downloads)283 void InProgressDownloadManager::GetAllDownloads(
284 SimpleDownloadManager::DownloadVector* downloads) {
285 for (auto& item : in_progress_downloads_)
286 downloads->push_back(item.get());
287 }
288
GetDownloadByGuid(const std::string & guid)289 DownloadItem* InProgressDownloadManager::GetDownloadByGuid(
290 const std::string& guid) {
291 for (auto& item : in_progress_downloads_) {
292 if (item->GetGuid() == guid)
293 return item.get();
294 }
295 return nullptr;
296 }
297
BeginDownload(std::unique_ptr<DownloadUrlParameters> params,std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_url_loader_factory,bool is_new_download,const GURL & site_url,const GURL & tab_url,const GURL & tab_referrer_url)298 void InProgressDownloadManager::BeginDownload(
299 std::unique_ptr<DownloadUrlParameters> params,
300 std::unique_ptr<network::PendingSharedURLLoaderFactory>
301 pending_url_loader_factory,
302 bool is_new_download,
303 const GURL& site_url,
304 const GURL& tab_url,
305 const GURL& tab_referrer_url) {
306 std::unique_ptr<network::ResourceRequest> request =
307 CreateResourceRequest(params.get());
308 mojo::PendingRemote<device::mojom::WakeLockProvider> wake_lock_provider;
309 if (wake_lock_provider_binder_) {
310 wake_lock_provider_binder_.Run(
311 wake_lock_provider.InitWithNewPipeAndPassReceiver());
312 }
313 GetIOTaskRunner()->PostTask(
314 FROM_HERE,
315 base::BindOnce(&BeginResourceDownload, std::move(params),
316 std::move(request), std::move(pending_url_loader_factory),
317 url_security_policy_, is_new_download,
318 weak_factory_.GetWeakPtr(), site_url, tab_url,
319 tab_referrer_url, std::move(wake_lock_provider),
320 !delegate_ /* is_background_mode */,
321 base::ThreadTaskRunnerHandle::Get()));
322 }
323
InterceptDownloadFromNavigation(std::unique_ptr<network::ResourceRequest> resource_request,int render_process_id,int render_frame_id,const GURL & site_url,const GURL & tab_url,const GURL & tab_referrer_url,std::vector<GURL> url_chain,net::CertStatus cert_status,network::mojom::URLResponseHeadPtr response_head,mojo::ScopedDataPipeConsumerHandle response_body,network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_url_loader_factory)324 void InProgressDownloadManager::InterceptDownloadFromNavigation(
325 std::unique_ptr<network::ResourceRequest> resource_request,
326 int render_process_id,
327 int render_frame_id,
328 const GURL& site_url,
329 const GURL& tab_url,
330 const GURL& tab_referrer_url,
331 std::vector<GURL> url_chain,
332 net::CertStatus cert_status,
333 network::mojom::URLResponseHeadPtr response_head,
334 mojo::ScopedDataPipeConsumerHandle response_body,
335 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
336 std::unique_ptr<network::PendingSharedURLLoaderFactory>
337 pending_url_loader_factory) {
338 mojo::PendingRemote<device::mojom::WakeLockProvider> wake_lock_provider;
339 if (wake_lock_provider_binder_) {
340 wake_lock_provider_binder_.Run(
341 wake_lock_provider.InitWithNewPipeAndPassReceiver());
342 }
343
344 GetIOTaskRunner()->PostTask(
345 FROM_HERE,
346 base::BindOnce(
347 &CreateDownloadHandlerForNavigation, weak_factory_.GetWeakPtr(),
348 std::move(resource_request), render_process_id, render_frame_id,
349 site_url, tab_url, tab_referrer_url, std::move(url_chain),
350 std::move(cert_status), std::move(response_head),
351 std::move(response_body), std::move(url_loader_client_endpoints),
352 std::move(pending_url_loader_factory), url_security_policy_,
353 std::move(wake_lock_provider), base::ThreadTaskRunnerHandle::Get()));
354 }
355
Initialize(const base::FilePath & in_progress_db_dir,leveldb_proto::ProtoDatabaseProvider * db_provider)356 void InProgressDownloadManager::Initialize(
357 const base::FilePath& in_progress_db_dir,
358 leveldb_proto::ProtoDatabaseProvider* db_provider) {
359 std::unique_ptr<DownloadDB> download_db;
360
361 if (in_progress_db_dir.empty()) {
362 download_db = std::make_unique<DownloadDB>();
363 } else {
364 download_db = std::make_unique<DownloadDBImpl>(
365 DownloadNamespace::NAMESPACE_BROWSER_DOWNLOAD, in_progress_db_dir,
366 db_provider);
367 }
368
369 download_db_cache_ =
370 std::make_unique<DownloadDBCache>(std::move(download_db));
371 if (GetDownloadDBTaskRunnerForTesting()) {
372 download_db_cache_->SetTimerTaskRunnerForTesting(
373 GetDownloadDBTaskRunnerForTesting());
374 }
375 download_db_cache_->Initialize(base::BindOnce(
376 &InProgressDownloadManager::OnDBInitialized, weak_factory_.GetWeakPtr()));
377 }
378
ShutDown()379 void InProgressDownloadManager::ShutDown() {
380 url_download_handlers_.clear();
381 }
382
DetermineDownloadTarget(DownloadItemImpl * download,DownloadTargetCallback callback)383 void InProgressDownloadManager::DetermineDownloadTarget(
384 DownloadItemImpl* download,
385 DownloadTargetCallback callback) {
386 base::FilePath target_path = download->GetForcedFilePath().empty()
387 ? download->GetTargetFilePath()
388 : download->GetForcedFilePath();
389 #if defined(OS_ANDROID)
390 if (target_path.empty()) {
391 std::move(callback).Run(
392 target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
393 download->GetDangerType(), download->GetMixedContentStatus(),
394 target_path, DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
395 RecordBackgroundTargetDeterminationResult(
396 BackgroudTargetDeterminationResultTypes::kTargetPathMissing);
397 return;
398 }
399
400 // If final target is a content URI, the intermediate path should
401 // be identical to it.
402 if (target_path.IsContentUri()) {
403 std::move(callback).Run(
404 target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
405 download->GetDangerType(), download->GetMixedContentStatus(),
406 target_path, DOWNLOAD_INTERRUPT_REASON_NONE);
407 RecordBackgroundTargetDeterminationResult(
408 BackgroudTargetDeterminationResultTypes::kSuccess);
409 return;
410 }
411
412 DownloadPathReservationTracker::GetReservedPath(
413 download, target_path, target_path.DirName(), default_download_dir_,
414 true /* create_directory */,
415 download->GetForcedFilePath().empty()
416 ? DownloadPathReservationTracker::UNIQUIFY
417 : DownloadPathReservationTracker::OVERWRITE,
418 base::BindOnce(&OnPathReserved, std::move(callback),
419 download->GetDangerType(),
420 download->GetMixedContentStatus(), intermediate_path_cb_,
421 download->GetForcedFilePath()));
422 #else
423 // For non-android, the code below is only used by tests.
424 base::FilePath intermediate_path =
425 download->GetFullPath().empty() ? target_path : download->GetFullPath();
426 std::move(callback).Run(
427 target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
428 download->GetDangerType(), download->GetMixedContentStatus(),
429 intermediate_path, DOWNLOAD_INTERRUPT_REASON_NONE);
430 #endif // defined(OS_ANDROID)
431 }
432
ResumeInterruptedDownload(std::unique_ptr<DownloadUrlParameters> params,const GURL & site_url)433 void InProgressDownloadManager::ResumeInterruptedDownload(
434 std::unique_ptr<DownloadUrlParameters> params,
435 const GURL& site_url) {
436 if (!url_loader_factory_)
437 return;
438
439 BeginDownload(std::move(params), url_loader_factory_->Clone(), false,
440 site_url, GURL(), GURL());
441 }
442
ShouldOpenDownload(DownloadItemImpl * item,ShouldOpenDownloadCallback callback)443 bool InProgressDownloadManager::ShouldOpenDownload(
444 DownloadItemImpl* item,
445 ShouldOpenDownloadCallback callback) {
446 return true;
447 }
448
ReportBytesWasted(DownloadItemImpl * download)449 void InProgressDownloadManager::ReportBytesWasted(DownloadItemImpl* download) {
450 download_db_cache_->OnDownloadUpdated(download);
451 }
452
RemoveInProgressDownload(const std::string & guid)453 void InProgressDownloadManager::RemoveInProgressDownload(
454 const std::string& guid) {
455 download_db_cache_->RemoveEntry(guid);
456 }
457
StartDownload(std::unique_ptr<DownloadCreateInfo> info,std::unique_ptr<InputStream> stream,URLLoaderFactoryProvider::URLLoaderFactoryProviderPtr url_loader_factory_provider,DownloadJob::CancelRequestCallback cancel_request_callback,DownloadUrlParameters::OnStartedCallback on_started)458 void InProgressDownloadManager::StartDownload(
459 std::unique_ptr<DownloadCreateInfo> info,
460 std::unique_ptr<InputStream> stream,
461 URLLoaderFactoryProvider::URLLoaderFactoryProviderPtr
462 url_loader_factory_provider,
463 DownloadJob::CancelRequestCallback cancel_request_callback,
464 DownloadUrlParameters::OnStartedCallback on_started) {
465 DCHECK(info);
466
467 if (info->is_new_download &&
468 (info->result == DOWNLOAD_INTERRUPT_REASON_NONE ||
469 info->result ==
470 DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT)) {
471 if (delegate_ && delegate_->InterceptDownload(*info)) {
472 if (cancel_request_callback)
473 std::move(cancel_request_callback).Run(false);
474 GetDownloadTaskRunner()->DeleteSoon(FROM_HERE, stream.release());
475 return;
476 }
477 }
478
479 // |stream| is only non-null if the download request was successful.
480 DCHECK(
481 (info->result == DOWNLOAD_INTERRUPT_REASON_NONE && !stream->IsEmpty()) ||
482 (info->result != DOWNLOAD_INTERRUPT_REASON_NONE && stream->IsEmpty()));
483 DVLOG(20) << __func__
484 << "() result=" << DownloadInterruptReasonToString(info->result);
485
486 GURL url = info->url();
487 std::vector<GURL> url_chain = info->url_chain;
488 std::string mime_type = info->mime_type;
489
490 if (info->is_new_download) {
491 RecordDownloadContentTypeSecurity(info->url(), info->url_chain,
492 info->mime_type, is_origin_secure_cb_);
493 }
494
495 // If the download cannot be found locally, ask |delegate_| to provide the
496 // DownloadItem.
497 if (delegate_ && !GetDownloadByGuid(info->guid)) {
498 delegate_->StartDownloadItem(
499 std::move(info), std::move(on_started),
500 base::BindOnce(&InProgressDownloadManager::StartDownloadWithItem,
501 weak_factory_.GetWeakPtr(), std::move(stream),
502 std::move(url_loader_factory_provider),
503 std::move(cancel_request_callback)));
504 } else {
505 std::string guid = info->guid;
506 if (info->is_new_download) {
507 auto download = std::make_unique<DownloadItemImpl>(
508 this, DownloadItem::kInvalidId, *info);
509 OnNewDownloadCreated(download.get());
510 guid = download->GetGuid();
511 DCHECK(!guid.empty());
512 in_progress_downloads_.push_back(std::move(download));
513 }
514 StartDownloadWithItem(
515 std::move(stream), std::move(url_loader_factory_provider),
516 std::move(cancel_request_callback), std::move(info),
517 static_cast<DownloadItemImpl*>(GetDownloadByGuid(guid)), false);
518 }
519 }
520
StartDownloadWithItem(std::unique_ptr<InputStream> stream,URLLoaderFactoryProvider::URLLoaderFactoryProviderPtr url_loader_factory_provider,DownloadJob::CancelRequestCallback cancel_request_callback,std::unique_ptr<DownloadCreateInfo> info,DownloadItemImpl * download,bool should_persist_new_download)521 void InProgressDownloadManager::StartDownloadWithItem(
522 std::unique_ptr<InputStream> stream,
523 URLLoaderFactoryProvider::URLLoaderFactoryProviderPtr
524 url_loader_factory_provider,
525 DownloadJob::CancelRequestCallback cancel_request_callback,
526 std::unique_ptr<DownloadCreateInfo> info,
527 DownloadItemImpl* download,
528 bool should_persist_new_download) {
529 if (!download) {
530 // If the download is no longer known to the DownloadManager, then it was
531 // removed after it was resumed. Ignore. If the download is cancelled
532 // while resuming, then also ignore the request.
533 if (cancel_request_callback)
534 std::move(cancel_request_callback).Run(false);
535 // The ByteStreamReader lives and dies on the download sequence.
536 if (info->result == DOWNLOAD_INTERRUPT_REASON_NONE)
537 GetDownloadTaskRunner()->DeleteSoon(FROM_HERE, stream.release());
538 return;
539 }
540
541 base::FilePath default_download_directory;
542 if (delegate_)
543 default_download_directory = delegate_->GetDefaultDownloadDirectory();
544
545 if (info->is_new_download && !should_persist_new_download)
546 non_persistent_download_guids_.insert(download->GetGuid());
547 // If the download is not persisted, don't notify |download_db_cache_|.
548 if (!base::Contains(non_persistent_download_guids_, download->GetGuid())) {
549 download_db_cache_->AddOrReplaceEntry(
550 CreateDownloadDBEntryFromItem(*download));
551 download->RemoveObserver(download_db_cache_.get());
552 download->AddObserver(download_db_cache_.get());
553 }
554
555 std::unique_ptr<DownloadFile> download_file;
556 if (info->result == DOWNLOAD_INTERRUPT_REASON_NONE) {
557 DCHECK(stream);
558 download_file.reset(file_factory_->CreateFile(
559 std::move(info->save_info), default_download_directory,
560 std::move(stream), download->GetId(),
561 download->DestinationObserverAsWeakPtr()));
562 }
563 // It is important to leave info->save_info intact in the case of an interrupt
564 // so that the DownloadItem can salvage what it can out of a failed
565 // resumption attempt.
566
567 download->Start(std::move(download_file), std::move(cancel_request_callback),
568 *info, std::move(url_loader_factory_provider));
569
570 if (download_start_observer_)
571 download_start_observer_->OnDownloadStarted(download);
572 }
573
OnDBInitialized(bool success,std::unique_ptr<std::vector<DownloadDBEntry>> entries)574 void InProgressDownloadManager::OnDBInitialized(
575 bool success,
576 std::unique_ptr<std::vector<DownloadDBEntry>> entries) {
577 #if defined(OS_ANDROID)
578 if (entries->size() > 0 &&
579 DownloadCollectionBridge::NeedToRetrieveDisplayNames()) {
580 DownloadCollectionBridge::GetDisplayNamesCallback callback =
581 base::BindOnce(&InProgressDownloadManager::OnDownloadNamesRetrieved,
582 weak_factory_.GetWeakPtr(), std::move(entries));
583 GetDownloadTaskRunner()->PostTask(
584 FROM_HERE,
585 base::BindOnce(
586 &DownloadCollectionBridge::GetDisplayNamesForDownloads,
587 base::BindOnce(&OnDownloadDisplayNamesReturned, std::move(callback),
588 base::ThreadTaskRunnerHandle::Get())));
589 return;
590 }
591 #endif
592 OnDownloadNamesRetrieved(std::move(entries), nullptr);
593 }
594
OnDownloadNamesRetrieved(std::unique_ptr<std::vector<DownloadDBEntry>> entries,DisplayNames display_names)595 void InProgressDownloadManager::OnDownloadNamesRetrieved(
596 std::unique_ptr<std::vector<DownloadDBEntry>> entries,
597 DisplayNames display_names) {
598 std::set<uint32_t> download_ids;
599 int num_duplicates = 0;
600 display_names_ = std::move(display_names);
601 for (const auto& entry : *entries) {
602 auto item = CreateDownloadItemImpl(
603 this, entry, CreateDownloadEntryFromDownloadDBEntry(entry));
604 if (!item)
605 continue;
606 uint32_t download_id = item->GetId();
607 // Remove entries with duplicate ids.
608 if (download_id != DownloadItem::kInvalidId &&
609 base::Contains(download_ids, download_id)) {
610 RemoveInProgressDownload(item->GetGuid());
611 num_duplicates++;
612 continue;
613 }
614 #if defined(OS_ANDROID)
615 const base::FilePath& path = item->GetTargetFilePath();
616 if (path.IsContentUri()) {
617 base::FilePath display_name = GetDownloadDisplayName(path);
618 // If a download doesn't have a display name, remove it.
619 if (display_name.empty()) {
620 RemoveInProgressDownload(item->GetGuid());
621 continue;
622 } else {
623 item->SetDisplayName(display_name);
624 }
625 }
626 #endif
627 item->AddObserver(download_db_cache_.get());
628 OnNewDownloadCreated(item.get());
629 in_progress_downloads_.emplace_back(std::move(item));
630 download_ids.insert(download_id);
631 }
632 if (num_duplicates > 0)
633 RecordDuplicateInProgressDownloadIdCount(num_duplicates);
634 OnInitialized();
635 OnDownloadsInitialized();
636 }
637
638 std::vector<std::unique_ptr<download::DownloadItemImpl>>
TakeInProgressDownloads()639 InProgressDownloadManager::TakeInProgressDownloads() {
640 return std::move(in_progress_downloads_);
641 }
642
GetDownloadDisplayName(const base::FilePath & path)643 base::FilePath InProgressDownloadManager::GetDownloadDisplayName(
644 const base::FilePath& path) {
645 #if defined(OS_ANDROID)
646 if (!display_names_)
647 return base::FilePath();
648 auto iter = display_names_->find(path.value());
649 if (iter != display_names_->end())
650 return iter->second;
651 #endif
652 return base::FilePath();
653 }
654
OnAllInprogressDownloadsLoaded()655 void InProgressDownloadManager::OnAllInprogressDownloadsLoaded() {
656 display_names_.reset();
657 }
658
SetDelegate(Delegate * delegate)659 void InProgressDownloadManager::SetDelegate(Delegate* delegate) {
660 delegate_ = delegate;
661 if (initialized_)
662 OnDownloadsInitialized();
663 }
664
OnDownloadsInitialized()665 void InProgressDownloadManager::OnDownloadsInitialized() {
666 if (delegate_) {
667 base::ThreadTaskRunnerHandle::Get()->PostTask(
668 FROM_HERE,
669 base::BindOnce(&InProgressDownloadManager::NotifyDownloadsInitialized,
670 weak_factory_.GetWeakPtr()));
671 }
672 }
673
NotifyDownloadsInitialized()674 void InProgressDownloadManager::NotifyDownloadsInitialized() {
675 if (delegate_)
676 delegate_->OnDownloadsInitialized();
677 }
678
AddInProgressDownloadForTest(std::unique_ptr<download::DownloadItemImpl> download)679 void InProgressDownloadManager::AddInProgressDownloadForTest(
680 std::unique_ptr<download::DownloadItemImpl> download) {
681 in_progress_downloads_.push_back(std::move(download));
682 }
683
CancelUrlDownload(UrlDownloadHandler * downloader,bool user_cancel)684 void InProgressDownloadManager::CancelUrlDownload(
685 UrlDownloadHandler* downloader,
686 bool user_cancel) {
687 OnUrlDownloadStopped(downloader);
688 }
689
690 } // namespace download
691