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