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