Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / download / download_manager_impl.cc
1 // Copyright (c) 2012 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/browser/download/download_manager_impl.h"
6
7 #include <iterator>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/debug/alias.h"
12 #include "base/i18n/case_conversion.h"
13 #include "base/logging.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/stl_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/sys_string_conversions.h"
18 #include "base/supports_user_data.h"
19 #include "base/synchronization/lock.h"
20 #include "build/build_config.h"
21 #include "content/browser/byte_stream.h"
22 #include "content/browser/download/download_create_info.h"
23 #include "content/browser/download/download_file_factory.h"
24 #include "content/browser/download/download_item_factory.h"
25 #include "content/browser/download/download_item_impl.h"
26 #include "content/browser/download/download_stats.h"
27 #include "content/browser/loader/resource_dispatcher_host_impl.h"
28 #include "content/browser/renderer_host/render_view_host_impl.h"
29 #include "content/browser/web_contents/web_contents_impl.h"
30 #include "content/public/browser/browser_context.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/content_browser_client.h"
33 #include "content/public/browser/download_interrupt_reasons.h"
34 #include "content/public/browser/download_manager_delegate.h"
35 #include "content/public/browser/download_url_parameters.h"
36 #include "content/public/browser/notification_service.h"
37 #include "content/public/browser/notification_types.h"
38 #include "content/public/browser/render_process_host.h"
39 #include "content/public/browser/resource_context.h"
40 #include "content/public/browser/web_contents_delegate.h"
41 #include "content/public/common/referrer.h"
42 #include "net/base/load_flags.h"
43 #include "net/base/request_priority.h"
44 #include "net/base/upload_bytes_element_reader.h"
45 #include "net/base/upload_data_stream.h"
46 #include "net/url_request/url_request_context.h"
47
48 namespace content {
49 namespace {
50
51 void BeginDownload(scoped_ptr<DownloadUrlParameters> params,
52                    uint32 download_id) {
53   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
54   // ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and
55   // DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so
56   // we must down cast. RDHI is the only subclass of RDH as of 2012 May 4.
57   scoped_ptr<net::URLRequest> request(
58       params->resource_context()->GetRequestContext()->CreateRequest(
59           params->url(), net::DEFAULT_PRIORITY, NULL, NULL));
60   request->SetLoadFlags(request->load_flags() | params->load_flags());
61   request->set_method(params->method());
62   if (!params->post_body().empty()) {
63     const std::string& body = params->post_body();
64     scoped_ptr<net::UploadElementReader> reader(
65         net::UploadOwnedBytesElementReader::CreateWithString(body));
66     request->set_upload(make_scoped_ptr(
67         net::UploadDataStream::CreateWithReader(reader.Pass(), 0)));
68   }
69   if (params->post_id() >= 0) {
70     // The POST in this case does not have an actual body, and only works
71     // when retrieving data from cache. This is done because we don't want
72     // to do a re-POST without user consent, and currently don't have a good
73     // plan on how to display the UI for that.
74     DCHECK(params->prefer_cache());
75     DCHECK_EQ("POST", params->method());
76     ScopedVector<net::UploadElementReader> element_readers;
77     request->set_upload(make_scoped_ptr(
78         new net::UploadDataStream(element_readers.Pass(), params->post_id())));
79   }
80
81   // If we're not at the beginning of the file, retrieve only the remaining
82   // portion.
83   bool has_last_modified = !params->last_modified().empty();
84   bool has_etag = !params->etag().empty();
85
86   // If we've asked for a range, we want to make sure that we only
87   // get that range if our current copy of the information is good.
88   // We shouldn't be asked to continue if we don't have a verifier.
89   DCHECK(params->offset() == 0 || has_etag || has_last_modified);
90
91   if (params->offset() > 0) {
92     request->SetExtraRequestHeaderByName(
93         "Range",
94         base::StringPrintf("bytes=%" PRId64 "-", params->offset()),
95         true);
96
97     if (has_last_modified) {
98       request->SetExtraRequestHeaderByName("If-Unmodified-Since",
99                                            params->last_modified(),
100                                            true);
101     }
102     if (has_etag) {
103       request->SetExtraRequestHeaderByName("If-Match", params->etag(), true);
104     }
105   }
106
107   for (DownloadUrlParameters::RequestHeadersType::const_iterator iter
108            = params->request_headers_begin();
109        iter != params->request_headers_end();
110        ++iter) {
111     request->SetExtraRequestHeaderByName(
112         iter->first, iter->second, false /*overwrite*/);
113   }
114
115   scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
116   save_info->file_path = params->file_path();
117   save_info->suggested_name = params->suggested_name();
118   save_info->offset = params->offset();
119   save_info->hash_state = params->hash_state();
120   save_info->prompt_for_save_location = params->prompt();
121   save_info->file = params->GetFile();
122
123   ResourceDispatcherHost::Get()->BeginDownload(
124       request.Pass(),
125       params->referrer(),
126       params->content_initiated(),
127       params->resource_context(),
128       params->render_process_host_id(),
129       params->render_view_host_routing_id(),
130       params->prefer_cache(),
131       save_info.Pass(),
132       download_id,
133       params->callback());
134 }
135
136 class MapValueIteratorAdapter {
137  public:
138   explicit MapValueIteratorAdapter(
139       base::hash_map<int64, DownloadItem*>::const_iterator iter)
140     : iter_(iter) {
141   }
142   ~MapValueIteratorAdapter() {}
143
144   DownloadItem* operator*() { return iter_->second; }
145
146   MapValueIteratorAdapter& operator++() {
147     ++iter_;
148     return *this;
149   }
150
151   bool operator!=(const MapValueIteratorAdapter& that) const {
152     return iter_ != that.iter_;
153   }
154
155  private:
156   base::hash_map<int64, DownloadItem*>::const_iterator iter_;
157   // Allow copy and assign.
158 };
159
160 class DownloadItemFactoryImpl : public DownloadItemFactory {
161  public:
162   DownloadItemFactoryImpl() {}
163   virtual ~DownloadItemFactoryImpl() {}
164
165   virtual DownloadItemImpl* CreatePersistedItem(
166       DownloadItemImplDelegate* delegate,
167       uint32 download_id,
168       const base::FilePath& current_path,
169       const base::FilePath& target_path,
170       const std::vector<GURL>& url_chain,
171       const GURL& referrer_url,
172       const base::Time& start_time,
173       const base::Time& end_time,
174       const std::string& etag,
175       const std::string& last_modified,
176       int64 received_bytes,
177       int64 total_bytes,
178       DownloadItem::DownloadState state,
179       DownloadDangerType danger_type,
180       DownloadInterruptReason interrupt_reason,
181       bool opened,
182       const net::BoundNetLog& bound_net_log) OVERRIDE {
183     return new DownloadItemImpl(
184         delegate,
185         download_id,
186         current_path,
187         target_path,
188         url_chain,
189         referrer_url,
190         start_time,
191         end_time,
192         etag,
193         last_modified,
194         received_bytes,
195         total_bytes,
196         state,
197         danger_type,
198         interrupt_reason,
199         opened,
200         bound_net_log);
201   }
202
203   virtual DownloadItemImpl* CreateActiveItem(
204       DownloadItemImplDelegate* delegate,
205       uint32 download_id,
206       const DownloadCreateInfo& info,
207       const net::BoundNetLog& bound_net_log) OVERRIDE {
208     return new DownloadItemImpl(delegate, download_id, info, bound_net_log);
209   }
210
211   virtual DownloadItemImpl* CreateSavePageItem(
212       DownloadItemImplDelegate* delegate,
213       uint32 download_id,
214       const base::FilePath& path,
215       const GURL& url,
216       const std::string& mime_type,
217       scoped_ptr<DownloadRequestHandleInterface> request_handle,
218       const net::BoundNetLog& bound_net_log) OVERRIDE {
219     return new DownloadItemImpl(delegate, download_id, path, url,
220                                 mime_type, request_handle.Pass(),
221                                 bound_net_log);
222   }
223 };
224
225 }  // namespace
226
227 DownloadManagerImpl::DownloadManagerImpl(
228     net::NetLog* net_log,
229     BrowserContext* browser_context)
230     : item_factory_(new DownloadItemFactoryImpl()),
231       file_factory_(new DownloadFileFactory()),
232       history_size_(0),
233       shutdown_needed_(true),
234       browser_context_(browser_context),
235       delegate_(NULL),
236       net_log_(net_log),
237       weak_factory_(this) {
238   DCHECK(browser_context);
239 }
240
241 DownloadManagerImpl::~DownloadManagerImpl() {
242   DCHECK(!shutdown_needed_);
243 }
244
245 DownloadItemImpl* DownloadManagerImpl::CreateActiveItem(
246     uint32 id, const DownloadCreateInfo& info) {
247   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
248   DCHECK(!ContainsKey(downloads_, id));
249   net::BoundNetLog bound_net_log =
250       net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
251   DownloadItemImpl* download =
252       item_factory_->CreateActiveItem(this, id, info, bound_net_log);
253   downloads_[id] = download;
254   return download;
255 }
256
257 void DownloadManagerImpl::GetNextId(const DownloadIdCallback& callback) {
258   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
259   if (delegate_) {
260     delegate_->GetNextId(callback);
261     return;
262   }
263   static uint32 next_id = content::DownloadItem::kInvalidId + 1;
264   callback.Run(next_id++);
265 }
266
267 void DownloadManagerImpl::DetermineDownloadTarget(
268     DownloadItemImpl* item, const DownloadTargetCallback& callback) {
269   // Note that this next call relies on
270   // DownloadItemImplDelegate::DownloadTargetCallback and
271   // DownloadManagerDelegate::DownloadTargetCallback having the same
272   // type.  If the types ever diverge, gasket code will need to
273   // be written here.
274   if (!delegate_ || !delegate_->DetermineDownloadTarget(item, callback)) {
275     base::FilePath target_path = item->GetForcedFilePath();
276     // TODO(asanka): Determine a useful path if |target_path| is empty.
277     callback.Run(target_path,
278                  DownloadItem::TARGET_DISPOSITION_OVERWRITE,
279                  DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
280                  target_path);
281   }
282 }
283
284 bool DownloadManagerImpl::ShouldCompleteDownload(
285     DownloadItemImpl* item, const base::Closure& complete_callback) {
286   if (!delegate_ ||
287       delegate_->ShouldCompleteDownload(item, complete_callback)) {
288     return true;
289   }
290   // Otherwise, the delegate has accepted responsibility to run the
291   // callback when the download is ready for completion.
292   return false;
293 }
294
295 bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(
296     const base::FilePath& path) {
297   if (!delegate_)
298     return false;
299
300   return delegate_->ShouldOpenFileBasedOnExtension(path);
301 }
302
303 bool DownloadManagerImpl::ShouldOpenDownload(
304     DownloadItemImpl* item, const ShouldOpenDownloadCallback& callback) {
305   if (!delegate_)
306     return true;
307
308   // Relies on DownloadItemImplDelegate::ShouldOpenDownloadCallback and
309   // DownloadManagerDelegate::DownloadOpenDelayedCallback "just happening"
310   // to have the same type :-}.
311   return delegate_->ShouldOpenDownload(item, callback);
312 }
313
314 void DownloadManagerImpl::SetDelegate(DownloadManagerDelegate* delegate) {
315   delegate_ = delegate;
316 }
317
318 DownloadManagerDelegate* DownloadManagerImpl::GetDelegate() const {
319   return delegate_;
320 }
321
322 void DownloadManagerImpl::Shutdown() {
323   VLOG(20) << __FUNCTION__ << "()"
324            << " shutdown_needed_ = " << shutdown_needed_;
325   if (!shutdown_needed_)
326     return;
327   shutdown_needed_ = false;
328
329   FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown(this));
330   // TODO(benjhayden): Consider clearing observers_.
331
332   // If there are in-progress downloads, cancel them. This also goes for
333   // dangerous downloads which will remain in history if they aren't explicitly
334   // accepted or discarded. Canceling will remove the intermediate download
335   // file.
336   for (DownloadMap::iterator it = downloads_.begin(); it != downloads_.end();
337        ++it) {
338     DownloadItemImpl* download = it->second;
339     if (download->GetState() == DownloadItem::IN_PROGRESS)
340       download->Cancel(false);
341   }
342   STLDeleteValues(&downloads_);
343   downloads_.clear();
344
345   // We'll have nothing more to report to the observers after this point.
346   observers_.Clear();
347
348   if (delegate_)
349     delegate_->Shutdown();
350   delegate_ = NULL;
351 }
352
353 void DownloadManagerImpl::StartDownload(
354     scoped_ptr<DownloadCreateInfo> info,
355     scoped_ptr<ByteStreamReader> stream,
356     const DownloadUrlParameters::OnStartedCallback& on_started) {
357   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
358   DCHECK(info);
359   uint32 download_id = info->download_id;
360   const bool new_download = (download_id == content::DownloadItem::kInvalidId);
361   base::Callback<void(uint32)> got_id(base::Bind(
362       &DownloadManagerImpl::StartDownloadWithId,
363       weak_factory_.GetWeakPtr(),
364       base::Passed(info.Pass()),
365       base::Passed(stream.Pass()),
366       on_started,
367       new_download));
368   if (new_download) {
369     GetNextId(got_id);
370   } else {
371     got_id.Run(download_id);
372   }
373 }
374
375 void DownloadManagerImpl::StartDownloadWithId(
376     scoped_ptr<DownloadCreateInfo> info,
377     scoped_ptr<ByteStreamReader> stream,
378     const DownloadUrlParameters::OnStartedCallback& on_started,
379     bool new_download,
380     uint32 id) {
381   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
382   DCHECK_NE(content::DownloadItem::kInvalidId, id);
383   DownloadItemImpl* download = NULL;
384   if (new_download) {
385     download = CreateActiveItem(id, *info);
386   } else {
387     DownloadMap::iterator item_iterator = downloads_.find(id);
388     // Trying to resume an interrupted download.
389     if (item_iterator == downloads_.end() ||
390         (item_iterator->second->GetState() == DownloadItem::CANCELLED)) {
391       // If the download is no longer known to the DownloadManager, then it was
392       // removed after it was resumed. Ignore. If the download is cancelled
393       // while resuming, then also ignore the request.
394       info->request_handle.CancelRequest();
395       if (!on_started.is_null())
396         on_started.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
397       return;
398     }
399     download = item_iterator->second;
400     DCHECK_EQ(DownloadItem::INTERRUPTED, download->GetState());
401     download->MergeOriginInfoOnResume(*info);
402   }
403
404   base::FilePath default_download_directory;
405   if (delegate_) {
406     base::FilePath website_save_directory;  // Unused
407     bool skip_dir_check = false;            // Unused
408     delegate_->GetSaveDir(GetBrowserContext(), &website_save_directory,
409                           &default_download_directory, &skip_dir_check);
410   }
411
412   // Create the download file and start the download.
413   scoped_ptr<DownloadFile> download_file(
414       file_factory_->CreateFile(
415           info->save_info.Pass(), default_download_directory,
416           info->url(), info->referrer_url,
417           delegate_ && delegate_->GenerateFileHash(),
418           stream.Pass(), download->GetBoundNetLog(),
419           download->DestinationObserverAsWeakPtr()));
420
421   // Attach the client ID identifying the app to the AV system.
422   if (download_file.get() && delegate_) {
423     download_file->SetClientGuid(
424         delegate_->ApplicationClientIdForFileScanning());
425   }
426
427   scoped_ptr<DownloadRequestHandleInterface> req_handle(
428       new DownloadRequestHandle(info->request_handle));
429   download->Start(download_file.Pass(), req_handle.Pass());
430
431   // For interrupted downloads, Start() will transition the state to
432   // IN_PROGRESS and consumers will be notified via OnDownloadUpdated().
433   // For new downloads, we notify here, rather than earlier, so that
434   // the download_file is bound to download and all the usual
435   // setters (e.g. Cancel) work.
436   if (new_download)
437     FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, download));
438
439   if (!on_started.is_null())
440     on_started.Run(download, DOWNLOAD_INTERRUPT_REASON_NONE);
441 }
442
443 void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
444   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
445   for (DownloadMap::iterator it = downloads_.begin();
446        it != downloads_.end(); ++it) {
447     DownloadItemImpl* item = it->second;
448     CheckForFileRemoval(item);
449   }
450 }
451
452 void DownloadManagerImpl::CheckForFileRemoval(DownloadItemImpl* download_item) {
453   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
454   if ((download_item->GetState() == DownloadItem::COMPLETE) &&
455       !download_item->GetFileExternallyRemoved() &&
456       delegate_) {
457     delegate_->CheckForFileExistence(
458         download_item,
459         base::Bind(&DownloadManagerImpl::OnFileExistenceChecked,
460                    weak_factory_.GetWeakPtr(), download_item->GetId()));
461   }
462 }
463
464 void DownloadManagerImpl::OnFileExistenceChecked(uint32 download_id,
465                                                  bool result) {
466   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
467   if (!result) {  // File does not exist.
468     if (ContainsKey(downloads_, download_id))
469       downloads_[download_id]->OnDownloadedFileRemoved();
470   }
471 }
472
473 BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
474   return browser_context_;
475 }
476
477 void DownloadManagerImpl::CreateSavePackageDownloadItem(
478     const base::FilePath& main_file_path,
479     const GURL& page_url,
480     const std::string& mime_type,
481     scoped_ptr<DownloadRequestHandleInterface> request_handle,
482     const DownloadItemImplCreated& item_created) {
483   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
484   GetNextId(base::Bind(
485       &DownloadManagerImpl::CreateSavePackageDownloadItemWithId,
486       weak_factory_.GetWeakPtr(),
487       main_file_path,
488       page_url,
489       mime_type,
490       base::Passed(request_handle.Pass()),
491       item_created));
492 }
493
494 void DownloadManagerImpl::CreateSavePackageDownloadItemWithId(
495     const base::FilePath& main_file_path,
496     const GURL& page_url,
497     const std::string& mime_type,
498     scoped_ptr<DownloadRequestHandleInterface> request_handle,
499     const DownloadItemImplCreated& item_created,
500     uint32 id) {
501   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
502   DCHECK_NE(content::DownloadItem::kInvalidId, id);
503   DCHECK(!ContainsKey(downloads_, id));
504   net::BoundNetLog bound_net_log =
505       net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
506   DownloadItemImpl* download_item = item_factory_->CreateSavePageItem(
507       this,
508       id,
509       main_file_path,
510       page_url,
511       mime_type,
512       request_handle.Pass(),
513       bound_net_log);
514   downloads_[download_item->GetId()] = download_item;
515   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(
516       this, download_item));
517   if (!item_created.is_null())
518     item_created.Run(download_item);
519 }
520
521 void DownloadManagerImpl::OnSavePackageSuccessfullyFinished(
522     DownloadItem* download_item) {
523   FOR_EACH_OBSERVER(Observer, observers_,
524                     OnSavePackageSuccessfullyFinished(this, download_item));
525 }
526
527 // Resume a download of a specific URL. We send the request to the
528 // ResourceDispatcherHost, and let it send us responses like a regular
529 // download.
530 void DownloadManagerImpl::ResumeInterruptedDownload(
531     scoped_ptr<content::DownloadUrlParameters> params,
532     uint32 id) {
533   RecordDownloadSource(INITIATED_BY_RESUMPTION);
534   BrowserThread::PostTask(
535       BrowserThread::IO,
536       FROM_HERE,
537       base::Bind(&BeginDownload, base::Passed(&params), id));
538 }
539
540 void DownloadManagerImpl::SetDownloadItemFactoryForTesting(
541     scoped_ptr<DownloadItemFactory> item_factory) {
542   item_factory_ = item_factory.Pass();
543 }
544
545 void DownloadManagerImpl::SetDownloadFileFactoryForTesting(
546     scoped_ptr<DownloadFileFactory> file_factory) {
547   file_factory_ = file_factory.Pass();
548 }
549
550 DownloadFileFactory* DownloadManagerImpl::GetDownloadFileFactoryForTesting() {
551   return file_factory_.get();
552 }
553
554 void DownloadManagerImpl::DownloadRemoved(DownloadItemImpl* download) {
555   if (!download)
556     return;
557
558   uint32 download_id = download->GetId();
559   if (downloads_.erase(download_id) == 0)
560     return;
561   delete download;
562 }
563
564 int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
565                                                 base::Time remove_end) {
566   int count = 0;
567   DownloadMap::const_iterator it = downloads_.begin();
568   while (it != downloads_.end()) {
569     DownloadItemImpl* download = it->second;
570
571     // Increment done here to protect against invalidation below.
572     ++it;
573
574     if (download->GetStartTime() >= remove_begin &&
575         (remove_end.is_null() || download->GetStartTime() < remove_end) &&
576         (download->GetState() != DownloadItem::IN_PROGRESS)) {
577       // Erases the download from downloads_.
578       download->Remove();
579       count++;
580     }
581   }
582   return count;
583 }
584
585 int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) {
586   return RemoveDownloadsBetween(remove_begin, base::Time());
587 }
588
589 int DownloadManagerImpl::RemoveAllDownloads() {
590   // The null times make the date range unbounded.
591   int num_deleted = RemoveDownloadsBetween(base::Time(), base::Time());
592   RecordClearAllSize(num_deleted);
593   return num_deleted;
594 }
595
596 void DownloadManagerImpl::DownloadUrl(
597     scoped_ptr<DownloadUrlParameters> params) {
598   if (params->post_id() >= 0) {
599     // Check this here so that the traceback is more useful.
600     DCHECK(params->prefer_cache());
601     DCHECK_EQ("POST", params->method());
602   }
603   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
604       &BeginDownload, base::Passed(&params),
605       content::DownloadItem::kInvalidId));
606 }
607
608 void DownloadManagerImpl::AddObserver(Observer* observer) {
609   observers_.AddObserver(observer);
610 }
611
612 void DownloadManagerImpl::RemoveObserver(Observer* observer) {
613   observers_.RemoveObserver(observer);
614 }
615
616 DownloadItem* DownloadManagerImpl::CreateDownloadItem(
617     uint32 id,
618     const base::FilePath& current_path,
619     const base::FilePath& target_path,
620     const std::vector<GURL>& url_chain,
621     const GURL& referrer_url,
622     const base::Time& start_time,
623     const base::Time& end_time,
624     const std::string& etag,
625     const std::string& last_modified,
626     int64 received_bytes,
627     int64 total_bytes,
628     DownloadItem::DownloadState state,
629     DownloadDangerType danger_type,
630     DownloadInterruptReason interrupt_reason,
631     bool opened) {
632   if (ContainsKey(downloads_, id)) {
633     NOTREACHED();
634     return NULL;
635   }
636   DownloadItemImpl* item = item_factory_->CreatePersistedItem(
637       this,
638       id,
639       current_path,
640       target_path,
641       url_chain,
642       referrer_url,
643       start_time,
644       end_time,
645       etag,
646       last_modified,
647       received_bytes,
648       total_bytes,
649       state,
650       danger_type,
651       interrupt_reason,
652       opened,
653       net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD));
654   downloads_[id] = item;
655   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, item));
656   VLOG(20) << __FUNCTION__ << "() download = " << item->DebugString(true);
657   return item;
658 }
659
660 int DownloadManagerImpl::InProgressCount() const {
661   int count = 0;
662   for (DownloadMap::const_iterator it = downloads_.begin();
663        it != downloads_.end(); ++it) {
664     if (it->second->GetState() == DownloadItem::IN_PROGRESS)
665       ++count;
666   }
667   return count;
668 }
669
670 int DownloadManagerImpl::NonMaliciousInProgressCount() const {
671   int count = 0;
672   for (DownloadMap::const_iterator it = downloads_.begin();
673        it != downloads_.end(); ++it) {
674     if (it->second->GetState() == DownloadItem::IN_PROGRESS &&
675         it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_URL &&
676         it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT &&
677         it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST &&
678         it->second->GetDangerType() !=
679             DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED) {
680       ++count;
681     }
682   }
683   return count;
684 }
685
686 DownloadItem* DownloadManagerImpl::GetDownload(uint32 download_id) {
687   return ContainsKey(downloads_, download_id) ? downloads_[download_id] : NULL;
688 }
689
690 void DownloadManagerImpl::GetAllDownloads(DownloadVector* downloads) {
691   for (DownloadMap::iterator it = downloads_.begin();
692        it != downloads_.end(); ++it) {
693     downloads->push_back(it->second);
694   }
695 }
696
697 void DownloadManagerImpl::OpenDownload(DownloadItemImpl* download) {
698   int num_unopened = 0;
699   for (DownloadMap::iterator it = downloads_.begin();
700        it != downloads_.end(); ++it) {
701     DownloadItemImpl* item = it->second;
702     if ((item->GetState() == DownloadItem::COMPLETE) &&
703         !item->GetOpened())
704       ++num_unopened;
705   }
706   RecordOpensOutstanding(num_unopened);
707
708   if (delegate_)
709     delegate_->OpenDownload(download);
710 }
711
712 void DownloadManagerImpl::ShowDownloadInShell(DownloadItemImpl* download) {
713   if (delegate_)
714     delegate_->ShowDownloadInShell(download);
715 }
716
717 }  // namespace content