Home | History | Annotate | Download | only in download
      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));
     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_stream = params->GetFileStream();
    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, net::ERR_ABORTED);
    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, net::OK);
    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
    718