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, 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 std::string& mime_type,
    173       const std::string& original_mime_type,
    174       const base::Time& start_time,
    175       const base::Time& end_time,
    176       const std::string& etag,
    177       const std::string& last_modified,
    178       int64 received_bytes,
    179       int64 total_bytes,
    180       DownloadItem::DownloadState state,
    181       DownloadDangerType danger_type,
    182       DownloadInterruptReason interrupt_reason,
    183       bool opened,
    184       const net::BoundNetLog& bound_net_log) OVERRIDE {
    185     return new DownloadItemImpl(
    186         delegate,
    187         download_id,
    188         current_path,
    189         target_path,
    190         url_chain,
    191         referrer_url,
    192         mime_type,
    193         original_mime_type,
    194         start_time,
    195         end_time,
    196         etag,
    197         last_modified,
    198         received_bytes,
    199         total_bytes,
    200         state,
    201         danger_type,
    202         interrupt_reason,
    203         opened,
    204         bound_net_log);
    205   }
    206 
    207   virtual DownloadItemImpl* CreateActiveItem(
    208       DownloadItemImplDelegate* delegate,
    209       uint32 download_id,
    210       const DownloadCreateInfo& info,
    211       const net::BoundNetLog& bound_net_log) OVERRIDE {
    212     return new DownloadItemImpl(delegate, download_id, info, bound_net_log);
    213   }
    214 
    215   virtual DownloadItemImpl* CreateSavePageItem(
    216       DownloadItemImplDelegate* delegate,
    217       uint32 download_id,
    218       const base::FilePath& path,
    219       const GURL& url,
    220       const std::string& mime_type,
    221       scoped_ptr<DownloadRequestHandleInterface> request_handle,
    222       const net::BoundNetLog& bound_net_log) OVERRIDE {
    223     return new DownloadItemImpl(delegate, download_id, path, url,
    224                                 mime_type, request_handle.Pass(),
    225                                 bound_net_log);
    226   }
    227 };
    228 
    229 }  // namespace
    230 
    231 DownloadManagerImpl::DownloadManagerImpl(
    232     net::NetLog* net_log,
    233     BrowserContext* browser_context)
    234     : item_factory_(new DownloadItemFactoryImpl()),
    235       file_factory_(new DownloadFileFactory()),
    236       history_size_(0),
    237       shutdown_needed_(true),
    238       browser_context_(browser_context),
    239       delegate_(NULL),
    240       net_log_(net_log),
    241       weak_factory_(this) {
    242   DCHECK(browser_context);
    243 }
    244 
    245 DownloadManagerImpl::~DownloadManagerImpl() {
    246   DCHECK(!shutdown_needed_);
    247 }
    248 
    249 DownloadItemImpl* DownloadManagerImpl::CreateActiveItem(
    250     uint32 id, const DownloadCreateInfo& info) {
    251   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    252   DCHECK(!ContainsKey(downloads_, id));
    253   net::BoundNetLog bound_net_log =
    254       net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
    255   DownloadItemImpl* download =
    256       item_factory_->CreateActiveItem(this, id, info, bound_net_log);
    257   downloads_[id] = download;
    258   return download;
    259 }
    260 
    261 void DownloadManagerImpl::GetNextId(const DownloadIdCallback& callback) {
    262   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    263   if (delegate_) {
    264     delegate_->GetNextId(callback);
    265     return;
    266   }
    267   static uint32 next_id = content::DownloadItem::kInvalidId + 1;
    268   callback.Run(next_id++);
    269 }
    270 
    271 void DownloadManagerImpl::DetermineDownloadTarget(
    272     DownloadItemImpl* item, const DownloadTargetCallback& callback) {
    273   // Note that this next call relies on
    274   // DownloadItemImplDelegate::DownloadTargetCallback and
    275   // DownloadManagerDelegate::DownloadTargetCallback having the same
    276   // type.  If the types ever diverge, gasket code will need to
    277   // be written here.
    278   if (!delegate_ || !delegate_->DetermineDownloadTarget(item, callback)) {
    279     base::FilePath target_path = item->GetForcedFilePath();
    280     // TODO(asanka): Determine a useful path if |target_path| is empty.
    281     callback.Run(target_path,
    282                  DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    283                  DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
    284                  target_path);
    285   }
    286 }
    287 
    288 bool DownloadManagerImpl::ShouldCompleteDownload(
    289     DownloadItemImpl* item, const base::Closure& complete_callback) {
    290   if (!delegate_ ||
    291       delegate_->ShouldCompleteDownload(item, complete_callback)) {
    292     return true;
    293   }
    294   // Otherwise, the delegate has accepted responsibility to run the
    295   // callback when the download is ready for completion.
    296   return false;
    297 }
    298 
    299 bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(
    300     const base::FilePath& path) {
    301   if (!delegate_)
    302     return false;
    303 
    304   return delegate_->ShouldOpenFileBasedOnExtension(path);
    305 }
    306 
    307 bool DownloadManagerImpl::ShouldOpenDownload(
    308     DownloadItemImpl* item, const ShouldOpenDownloadCallback& callback) {
    309   if (!delegate_)
    310     return true;
    311 
    312   // Relies on DownloadItemImplDelegate::ShouldOpenDownloadCallback and
    313   // DownloadManagerDelegate::DownloadOpenDelayedCallback "just happening"
    314   // to have the same type :-}.
    315   return delegate_->ShouldOpenDownload(item, callback);
    316 }
    317 
    318 void DownloadManagerImpl::SetDelegate(DownloadManagerDelegate* delegate) {
    319   delegate_ = delegate;
    320 }
    321 
    322 DownloadManagerDelegate* DownloadManagerImpl::GetDelegate() const {
    323   return delegate_;
    324 }
    325 
    326 void DownloadManagerImpl::Shutdown() {
    327   VLOG(20) << __FUNCTION__ << "()"
    328            << " shutdown_needed_ = " << shutdown_needed_;
    329   if (!shutdown_needed_)
    330     return;
    331   shutdown_needed_ = false;
    332 
    333   FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown(this));
    334   // TODO(benjhayden): Consider clearing observers_.
    335 
    336   // If there are in-progress downloads, cancel them. This also goes for
    337   // dangerous downloads which will remain in history if they aren't explicitly
    338   // accepted or discarded. Canceling will remove the intermediate download
    339   // file.
    340   for (DownloadMap::iterator it = downloads_.begin(); it != downloads_.end();
    341        ++it) {
    342     DownloadItemImpl* download = it->second;
    343     if (download->GetState() == DownloadItem::IN_PROGRESS)
    344       download->Cancel(false);
    345   }
    346   STLDeleteValues(&downloads_);
    347   downloads_.clear();
    348 
    349   // We'll have nothing more to report to the observers after this point.
    350   observers_.Clear();
    351 
    352   if (delegate_)
    353     delegate_->Shutdown();
    354   delegate_ = NULL;
    355 }
    356 
    357 void DownloadManagerImpl::StartDownload(
    358     scoped_ptr<DownloadCreateInfo> info,
    359     scoped_ptr<ByteStreamReader> stream,
    360     const DownloadUrlParameters::OnStartedCallback& on_started) {
    361   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    362   DCHECK(info);
    363   uint32 download_id = info->download_id;
    364   const bool new_download = (download_id == content::DownloadItem::kInvalidId);
    365   base::Callback<void(uint32)> got_id(base::Bind(
    366       &DownloadManagerImpl::StartDownloadWithId,
    367       weak_factory_.GetWeakPtr(),
    368       base::Passed(info.Pass()),
    369       base::Passed(stream.Pass()),
    370       on_started,
    371       new_download));
    372   if (new_download) {
    373     GetNextId(got_id);
    374   } else {
    375     got_id.Run(download_id);
    376   }
    377 }
    378 
    379 void DownloadManagerImpl::StartDownloadWithId(
    380     scoped_ptr<DownloadCreateInfo> info,
    381     scoped_ptr<ByteStreamReader> stream,
    382     const DownloadUrlParameters::OnStartedCallback& on_started,
    383     bool new_download,
    384     uint32 id) {
    385   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    386   DCHECK_NE(content::DownloadItem::kInvalidId, id);
    387   DownloadItemImpl* download = NULL;
    388   if (new_download) {
    389     download = CreateActiveItem(id, *info);
    390   } else {
    391     DownloadMap::iterator item_iterator = downloads_.find(id);
    392     // Trying to resume an interrupted download.
    393     if (item_iterator == downloads_.end() ||
    394         (item_iterator->second->GetState() == DownloadItem::CANCELLED)) {
    395       // If the download is no longer known to the DownloadManager, then it was
    396       // removed after it was resumed. Ignore. If the download is cancelled
    397       // while resuming, then also ignore the request.
    398       info->request_handle.CancelRequest();
    399       if (!on_started.is_null())
    400         on_started.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
    401       return;
    402     }
    403     download = item_iterator->second;
    404     DCHECK_EQ(DownloadItem::INTERRUPTED, download->GetState());
    405     download->MergeOriginInfoOnResume(*info);
    406   }
    407 
    408   base::FilePath default_download_directory;
    409   if (delegate_) {
    410     base::FilePath website_save_directory;  // Unused
    411     bool skip_dir_check = false;            // Unused
    412     delegate_->GetSaveDir(GetBrowserContext(), &website_save_directory,
    413                           &default_download_directory, &skip_dir_check);
    414   }
    415 
    416   // Create the download file and start the download.
    417   scoped_ptr<DownloadFile> download_file(
    418       file_factory_->CreateFile(
    419           info->save_info.Pass(), default_download_directory,
    420           info->url(), info->referrer_url,
    421           delegate_ && delegate_->GenerateFileHash(),
    422           stream.Pass(), download->GetBoundNetLog(),
    423           download->DestinationObserverAsWeakPtr()));
    424 
    425   // Attach the client ID identifying the app to the AV system.
    426   if (download_file.get() && delegate_) {
    427     download_file->SetClientGuid(
    428         delegate_->ApplicationClientIdForFileScanning());
    429   }
    430 
    431   scoped_ptr<DownloadRequestHandleInterface> req_handle(
    432       new DownloadRequestHandle(info->request_handle));
    433   download->Start(download_file.Pass(), req_handle.Pass());
    434 
    435   // For interrupted downloads, Start() will transition the state to
    436   // IN_PROGRESS and consumers will be notified via OnDownloadUpdated().
    437   // For new downloads, we notify here, rather than earlier, so that
    438   // the download_file is bound to download and all the usual
    439   // setters (e.g. Cancel) work.
    440   if (new_download)
    441     FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, download));
    442 
    443   if (!on_started.is_null())
    444     on_started.Run(download, DOWNLOAD_INTERRUPT_REASON_NONE);
    445 }
    446 
    447 void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
    448   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    449   for (DownloadMap::iterator it = downloads_.begin();
    450        it != downloads_.end(); ++it) {
    451     DownloadItemImpl* item = it->second;
    452     CheckForFileRemoval(item);
    453   }
    454 }
    455 
    456 void DownloadManagerImpl::CheckForFileRemoval(DownloadItemImpl* download_item) {
    457   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    458   if ((download_item->GetState() == DownloadItem::COMPLETE) &&
    459       !download_item->GetFileExternallyRemoved() &&
    460       delegate_) {
    461     delegate_->CheckForFileExistence(
    462         download_item,
    463         base::Bind(&DownloadManagerImpl::OnFileExistenceChecked,
    464                    weak_factory_.GetWeakPtr(), download_item->GetId()));
    465   }
    466 }
    467 
    468 void DownloadManagerImpl::OnFileExistenceChecked(uint32 download_id,
    469                                                  bool result) {
    470   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    471   if (!result) {  // File does not exist.
    472     if (ContainsKey(downloads_, download_id))
    473       downloads_[download_id]->OnDownloadedFileRemoved();
    474   }
    475 }
    476 
    477 BrowserContext* DownloadManagerImpl::GetBrowserContext() const {
    478   return browser_context_;
    479 }
    480 
    481 void DownloadManagerImpl::CreateSavePackageDownloadItem(
    482     const base::FilePath& main_file_path,
    483     const GURL& page_url,
    484     const std::string& mime_type,
    485     scoped_ptr<DownloadRequestHandleInterface> request_handle,
    486     const DownloadItemImplCreated& item_created) {
    487   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    488   GetNextId(base::Bind(
    489       &DownloadManagerImpl::CreateSavePackageDownloadItemWithId,
    490       weak_factory_.GetWeakPtr(),
    491       main_file_path,
    492       page_url,
    493       mime_type,
    494       base::Passed(request_handle.Pass()),
    495       item_created));
    496 }
    497 
    498 void DownloadManagerImpl::CreateSavePackageDownloadItemWithId(
    499     const base::FilePath& main_file_path,
    500     const GURL& page_url,
    501     const std::string& mime_type,
    502     scoped_ptr<DownloadRequestHandleInterface> request_handle,
    503     const DownloadItemImplCreated& item_created,
    504     uint32 id) {
    505   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    506   DCHECK_NE(content::DownloadItem::kInvalidId, id);
    507   DCHECK(!ContainsKey(downloads_, id));
    508   net::BoundNetLog bound_net_log =
    509       net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD);
    510   DownloadItemImpl* download_item = item_factory_->CreateSavePageItem(
    511       this,
    512       id,
    513       main_file_path,
    514       page_url,
    515       mime_type,
    516       request_handle.Pass(),
    517       bound_net_log);
    518   downloads_[download_item->GetId()] = download_item;
    519   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(
    520       this, download_item));
    521   if (!item_created.is_null())
    522     item_created.Run(download_item);
    523 }
    524 
    525 void DownloadManagerImpl::OnSavePackageSuccessfullyFinished(
    526     DownloadItem* download_item) {
    527   FOR_EACH_OBSERVER(Observer, observers_,
    528                     OnSavePackageSuccessfullyFinished(this, download_item));
    529 }
    530 
    531 // Resume a download of a specific URL. We send the request to the
    532 // ResourceDispatcherHost, and let it send us responses like a regular
    533 // download.
    534 void DownloadManagerImpl::ResumeInterruptedDownload(
    535     scoped_ptr<content::DownloadUrlParameters> params,
    536     uint32 id) {
    537   RecordDownloadSource(INITIATED_BY_RESUMPTION);
    538   BrowserThread::PostTask(
    539       BrowserThread::IO,
    540       FROM_HERE,
    541       base::Bind(&BeginDownload, base::Passed(&params), id));
    542 }
    543 
    544 void DownloadManagerImpl::SetDownloadItemFactoryForTesting(
    545     scoped_ptr<DownloadItemFactory> item_factory) {
    546   item_factory_ = item_factory.Pass();
    547 }
    548 
    549 void DownloadManagerImpl::SetDownloadFileFactoryForTesting(
    550     scoped_ptr<DownloadFileFactory> file_factory) {
    551   file_factory_ = file_factory.Pass();
    552 }
    553 
    554 DownloadFileFactory* DownloadManagerImpl::GetDownloadFileFactoryForTesting() {
    555   return file_factory_.get();
    556 }
    557 
    558 void DownloadManagerImpl::DownloadRemoved(DownloadItemImpl* download) {
    559   if (!download)
    560     return;
    561 
    562   uint32 download_id = download->GetId();
    563   if (downloads_.erase(download_id) == 0)
    564     return;
    565   delete download;
    566 }
    567 
    568 int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
    569                                                 base::Time remove_end) {
    570   int count = 0;
    571   DownloadMap::const_iterator it = downloads_.begin();
    572   while (it != downloads_.end()) {
    573     DownloadItemImpl* download = it->second;
    574 
    575     // Increment done here to protect against invalidation below.
    576     ++it;
    577 
    578     if (download->GetStartTime() >= remove_begin &&
    579         (remove_end.is_null() || download->GetStartTime() < remove_end) &&
    580         (download->GetState() != DownloadItem::IN_PROGRESS)) {
    581       // Erases the download from downloads_.
    582       download->Remove();
    583       count++;
    584     }
    585   }
    586   return count;
    587 }
    588 
    589 int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) {
    590   return RemoveDownloadsBetween(remove_begin, base::Time());
    591 }
    592 
    593 int DownloadManagerImpl::RemoveAllDownloads() {
    594   // The null times make the date range unbounded.
    595   int num_deleted = RemoveDownloadsBetween(base::Time(), base::Time());
    596   RecordClearAllSize(num_deleted);
    597   return num_deleted;
    598 }
    599 
    600 void DownloadManagerImpl::DownloadUrl(
    601     scoped_ptr<DownloadUrlParameters> params) {
    602   if (params->post_id() >= 0) {
    603     // Check this here so that the traceback is more useful.
    604     DCHECK(params->prefer_cache());
    605     DCHECK_EQ("POST", params->method());
    606   }
    607   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
    608       &BeginDownload, base::Passed(&params),
    609       content::DownloadItem::kInvalidId));
    610 }
    611 
    612 void DownloadManagerImpl::AddObserver(Observer* observer) {
    613   observers_.AddObserver(observer);
    614 }
    615 
    616 void DownloadManagerImpl::RemoveObserver(Observer* observer) {
    617   observers_.RemoveObserver(observer);
    618 }
    619 
    620 DownloadItem* DownloadManagerImpl::CreateDownloadItem(
    621     uint32 id,
    622     const base::FilePath& current_path,
    623     const base::FilePath& target_path,
    624     const std::vector<GURL>& url_chain,
    625     const GURL& referrer_url,
    626     const std::string& mime_type,
    627     const std::string& original_mime_type,
    628     const base::Time& start_time,
    629     const base::Time& end_time,
    630     const std::string& etag,
    631     const std::string& last_modified,
    632     int64 received_bytes,
    633     int64 total_bytes,
    634     DownloadItem::DownloadState state,
    635     DownloadDangerType danger_type,
    636     DownloadInterruptReason interrupt_reason,
    637     bool opened) {
    638   if (ContainsKey(downloads_, id)) {
    639     NOTREACHED();
    640     return NULL;
    641   }
    642   DownloadItemImpl* item = item_factory_->CreatePersistedItem(
    643       this,
    644       id,
    645       current_path,
    646       target_path,
    647       url_chain,
    648       referrer_url,
    649       mime_type,
    650       original_mime_type,
    651       start_time,
    652       end_time,
    653       etag,
    654       last_modified,
    655       received_bytes,
    656       total_bytes,
    657       state,
    658       danger_type,
    659       interrupt_reason,
    660       opened,
    661       net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD));
    662   downloads_[id] = item;
    663   FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, item));
    664   VLOG(20) << __FUNCTION__ << "() download = " << item->DebugString(true);
    665   return item;
    666 }
    667 
    668 int DownloadManagerImpl::InProgressCount() const {
    669   int count = 0;
    670   for (DownloadMap::const_iterator it = downloads_.begin();
    671        it != downloads_.end(); ++it) {
    672     if (it->second->GetState() == DownloadItem::IN_PROGRESS)
    673       ++count;
    674   }
    675   return count;
    676 }
    677 
    678 int DownloadManagerImpl::NonMaliciousInProgressCount() const {
    679   int count = 0;
    680   for (DownloadMap::const_iterator it = downloads_.begin();
    681        it != downloads_.end(); ++it) {
    682     if (it->second->GetState() == DownloadItem::IN_PROGRESS &&
    683         it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_URL &&
    684         it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT &&
    685         it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST &&
    686         it->second->GetDangerType() !=
    687             DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED) {
    688       ++count;
    689     }
    690   }
    691   return count;
    692 }
    693 
    694 DownloadItem* DownloadManagerImpl::GetDownload(uint32 download_id) {
    695   return ContainsKey(downloads_, download_id) ? downloads_[download_id] : NULL;
    696 }
    697 
    698 void DownloadManagerImpl::GetAllDownloads(DownloadVector* downloads) {
    699   for (DownloadMap::iterator it = downloads_.begin();
    700        it != downloads_.end(); ++it) {
    701     downloads->push_back(it->second);
    702   }
    703 }
    704 
    705 void DownloadManagerImpl::OpenDownload(DownloadItemImpl* download) {
    706   int num_unopened = 0;
    707   for (DownloadMap::iterator it = downloads_.begin();
    708        it != downloads_.end(); ++it) {
    709     DownloadItemImpl* item = it->second;
    710     if ((item->GetState() == DownloadItem::COMPLETE) &&
    711         !item->GetOpened())
    712       ++num_unopened;
    713   }
    714   RecordOpensOutstanding(num_unopened);
    715 
    716   if (delegate_)
    717     delegate_->OpenDownload(download);
    718 }
    719 
    720 void DownloadManagerImpl::ShowDownloadInShell(DownloadItemImpl* download) {
    721   if (delegate_)
    722     delegate_->ShowDownloadInShell(download);
    723 }
    724 
    725 }  // namespace content
    726