diff options
author | Torne (Richard Coles) <torne@google.com> | 2013-03-28 15:31:22 +0000 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2013-03-28 15:31:22 +0000 |
commit | 2a99a7e74a7f215066514fe81d2bfa6639d9eddd (patch) | |
tree | 7c2d04841fcd599fd83b0f0bb1100e1c89a35bae /content/browser/download/download_manager_impl.cc | |
parent | 61c449bbbb53310a8c041d8cefdd6b01a126cc7e (diff) | |
download | chromium_org-2a99a7e74a7f215066514fe81d2bfa6639d9eddd.tar.gz |
Merge from Chromium at DEPS revision r190564
This commit was generated by merge_to_master.py.
Change-Id: Icadecbce29854b8fa25fd335b2c1949b5ca5d170
Diffstat (limited to 'content/browser/download/download_manager_impl.cc')
-rw-r--r-- | content/browser/download/download_manager_impl.cc | 641 |
1 files changed, 233 insertions, 408 deletions
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc index 3da3f56589..0e28d16cc4 100644 --- a/content/browser/download/download_manager_impl.cc +++ b/content/browser/download/download_manager_impl.cc @@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/callback.h" #include "base/debug/alias.h" -#include "base/file_util.h" #include "base/i18n/case_conversion.h" #include "base/logging.h" #include "base/message_loop.h" @@ -19,36 +18,38 @@ #include "base/synchronization/lock.h" #include "base/sys_string_conversions.h" #include "build/build_config.h" -#include "content/browser/download/byte_stream.h" +#include "content/browser/byte_stream.h" #include "content/browser/download/download_create_info.h" #include "content/browser/download/download_file_factory.h" #include "content/browser/download/download_item_factory.h" #include "content/browser/download/download_item_impl.h" #include "content/browser/download/download_stats.h" +#include "content/browser/loader/resource_dispatcher_host_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" -#include "content/browser/renderer_host/resource_dispatcher_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/download_interrupt_reasons.h" #include "content/public/browser/download_manager_delegate.h" -#include "content/public/browser/download_persistent_store_info.h" #include "content/public/browser/download_url_parameters.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/resource_context.h" #include "content/public/browser/web_contents_delegate.h" +#include "content/public/common/referrer.h" #include "net/base/load_flags.h" -#include "net/base/upload_data.h" +#include "net/base/upload_bytes_element_reader.h" +#include "net/base/upload_data_stream.h" #include "net/url_request/url_request_context.h" #include "webkit/glue/webkit_glue.h" namespace content { namespace { -void BeginDownload(scoped_ptr<DownloadUrlParameters> params) { +void BeginDownload(scoped_ptr<DownloadUrlParameters> params, + DownloadId download_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and // DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so @@ -56,14 +57,19 @@ void BeginDownload(scoped_ptr<DownloadUrlParameters> params) { scoped_ptr<net::URLRequest> request( params->resource_context()->GetRequestContext()->CreateRequest( params->url(), NULL)); - request->set_referrer(params->referrer().url.spec()); + if (params->referrer().url.is_valid()) + request->set_referrer(params->referrer().url.spec()); webkit_glue::ConfigureURLRequestForReferrerPolicy( request.get(), params->referrer().policy); request->set_load_flags(request->load_flags() | params->load_flags()); request->set_method(params->method()); - if (!params->post_body().empty()) - request->AppendBytesToUpload(params->post_body().data(), - params->post_body().size()); + if (!params->post_body().empty()) { + const std::string& body = params->post_body(); + scoped_ptr<net::UploadElementReader> reader( + net::UploadOwnedBytesElementReader::CreateWithString(body)); + request->set_upload(make_scoped_ptr( + net::UploadDataStream::CreateWithReader(reader.Pass(), 0))); + } if (params->post_id() >= 0) { // The POST in this case does not have an actual body, and only works // when retrieving data from cache. This is done because we don't want @@ -71,10 +77,37 @@ void BeginDownload(scoped_ptr<DownloadUrlParameters> params) { // plan on how to display the UI for that. DCHECK(params->prefer_cache()); DCHECK(params->method() == "POST"); - scoped_refptr<net::UploadData> upload_data = new net::UploadData(); - upload_data->set_identifier(params->post_id()); - request->set_upload(upload_data); + ScopedVector<net::UploadElementReader> element_readers; + request->set_upload(make_scoped_ptr( + new net::UploadDataStream(&element_readers, params->post_id()))); + } + + // If we're not at the beginning of the file, retrieve only the remaining + // portion. + bool has_last_modified = !params->last_modified().empty(); + bool has_etag = !params->etag().empty(); + + // If we've asked for a range, we want to make sure that we only + // get that range if our current copy of the information is good. + // We shouldn't be asked to continue if we don't have a verifier. + DCHECK(params->offset() == 0 || has_etag || has_last_modified); + + if (params->offset() > 0) { + request->SetExtraRequestHeaderByName( + "Range", + base::StringPrintf("bytes=%" PRId64 "-", params->offset()), + true); + + if (has_last_modified) { + request->SetExtraRequestHeaderByName("If-Unmodified-Since", + params->last_modified(), + true); + } + if (has_etag) { + request->SetExtraRequestHeaderByName("If-Match", params->etag(), true); + } } + for (DownloadUrlParameters::RequestHeadersType::const_iterator iter = params->request_headers_begin(); iter != params->request_headers_end(); @@ -99,6 +132,7 @@ void BeginDownload(scoped_ptr<DownloadUrlParameters> params) { params->render_view_host_routing_id(), params->prefer_cache(), save_info.Pass(), + download_id, params->callback()); } @@ -135,36 +169,62 @@ void EnsureNoPendingDownloadJobsOnFile(bool* result) { class DownloadItemFactoryImpl : public DownloadItemFactory { public: - DownloadItemFactoryImpl() {} - virtual ~DownloadItemFactoryImpl() {} - - virtual DownloadItemImpl* CreatePersistedItem( - DownloadItemImplDelegate* delegate, - DownloadId download_id, - const DownloadPersistentStoreInfo& info, - const net::BoundNetLog& bound_net_log) OVERRIDE { - return new DownloadItemImpl(delegate, download_id, info, bound_net_log); - } + DownloadItemFactoryImpl() {} + virtual ~DownloadItemFactoryImpl() {} + + virtual DownloadItemImpl* CreatePersistedItem( + DownloadItemImplDelegate* delegate, + DownloadId download_id, + const base::FilePath& current_path, + const base::FilePath& target_path, + const std::vector<GURL>& url_chain, + const GURL& referrer_url, + const base::Time& start_time, + const base::Time& end_time, + int64 received_bytes, + int64 total_bytes, + DownloadItem::DownloadState state, + DownloadDangerType danger_type, + DownloadInterruptReason interrupt_reason, + bool opened, + const net::BoundNetLog& bound_net_log) OVERRIDE { + return new DownloadItemImpl( + delegate, + download_id, + current_path, + target_path, + url_chain, + referrer_url, + start_time, + end_time, + received_bytes, + total_bytes, + state, + danger_type, + interrupt_reason, + opened, + bound_net_log); + } - virtual DownloadItemImpl* CreateActiveItem( - DownloadItemImplDelegate* delegate, - const DownloadCreateInfo& info, - scoped_ptr<DownloadRequestHandleInterface> request_handle, - const net::BoundNetLog& bound_net_log) OVERRIDE { - return new DownloadItemImpl(delegate, info, request_handle.Pass(), - bound_net_log); - } + virtual DownloadItemImpl* CreateActiveItem( + DownloadItemImplDelegate* delegate, + const DownloadCreateInfo& info, + const net::BoundNetLog& bound_net_log) OVERRIDE { + return new DownloadItemImpl(delegate, info, bound_net_log); + } - virtual DownloadItemImpl* CreateSavePageItem( - DownloadItemImplDelegate* delegate, - const FilePath& path, - const GURL& url, - DownloadId download_id, - const std::string& mime_type, - const net::BoundNetLog& bound_net_log) OVERRIDE { - return new DownloadItemImpl(delegate, path, url, download_id, - mime_type, bound_net_log); - } + virtual DownloadItemImpl* CreateSavePageItem( + DownloadItemImplDelegate* delegate, + const base::FilePath& path, + const GURL& url, + DownloadId download_id, + const std::string& mime_type, + scoped_ptr<DownloadRequestHandleInterface> request_handle, + const net::BoundNetLog& bound_net_log) OVERRIDE { + return new DownloadItemImpl(delegate, path, url, download_id, + mime_type, request_handle.Pass(), + bound_net_log); + } }; } // namespace @@ -204,7 +264,7 @@ void DownloadManagerImpl::DetermineDownloadTarget( // type. If the types ever diverge, gasket code will need to // be written here. if (!delegate_ || !delegate_->DetermineDownloadTarget(item, callback)) { - FilePath target_path = item->GetForcedFilePath(); + base::FilePath target_path = item->GetForcedFilePath(); // TODO(asanka): Determine a useful path if |target_path| is empty. callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE, @@ -213,17 +273,19 @@ void DownloadManagerImpl::DetermineDownloadTarget( } } -void DownloadManagerImpl::ReadyForDownloadCompletion( +bool DownloadManagerImpl::ShouldCompleteDownload( DownloadItemImpl* item, const base::Closure& complete_callback) { if (!delegate_ || delegate_->ShouldCompleteDownload(item, complete_callback)) { - complete_callback.Run(); + return true; } // Otherwise, the delegate has accepted responsibility to run the // callback when the download is ready for completion. + return false; } -bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension(const FilePath& path) { +bool DownloadManagerImpl::ShouldOpenFileBasedOnExtension( + const base::FilePath& path) { if (!delegate_) return false; @@ -259,8 +321,6 @@ void DownloadManagerImpl::Shutdown() { FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown(this)); // TODO(benjhayden): Consider clearing observers_. - AssertContainersConsistent(); - // Go through all downloads in downloads_. Dangerous ones we need to // remove on disk, and in progress ones we need to cancel. for (DownloadMap::iterator it = downloads_.begin(); it != downloads_.end();) { @@ -271,8 +331,7 @@ void DownloadManagerImpl::Shutdown() { // associative containers such as sets. it++; - if (download->GetSafetyState() == DownloadItem::DANGEROUS && - download->IsPartialDownload()) { + if (download->IsDangerous() && download->IsPartialDownload()) { // The user hasn't accepted it, so we need to remove it // from the disk. This may or may not result in it being // removed from the DownloadManager queues and deleted @@ -284,8 +343,6 @@ void DownloadManagerImpl::Shutdown() { download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN); } else if (download->IsPartialDownload()) { download->Cancel(false); - if (delegate_) - delegate_->UpdateItemInPersistentStore(download); } } @@ -293,12 +350,7 @@ void DownloadManagerImpl::Shutdown() { // and all in progress downloads have been cancelled. We can now delete // anything left. - // We delete the downloads before clearing the active_downloads_ map - // so that downloads in the COMPLETING_INTERNAL state (which will have - // ignored the Cancel() above) will still show up in active_downloads_ - // in order to satisfy the invariants enforced in AssertStateConsistent(). STLDeleteValues(&downloads_); - active_downloads_.clear(); downloads_.clear(); // We'll have nothing more to report to the observers after this point. @@ -324,13 +376,10 @@ DownloadItem* DownloadManagerImpl::StartDownload( scoped_ptr<ByteStreamReader> stream) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - net::BoundNetLog bound_net_log = - net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD); - - FilePath default_download_directory; + base::FilePath default_download_directory; if (delegate_) { - FilePath website_save_directory; // Unused - bool skip_dir_check = false; // Unused + base::FilePath website_save_directory; // Unused + bool skip_dir_check = false; // Unused delegate_->GetSaveDir(GetBrowserContext(), &website_save_directory, &default_download_directory, &skip_dir_check); } @@ -338,16 +387,17 @@ DownloadItem* DownloadManagerImpl::StartDownload( // We create the DownloadItem before the DownloadFile because the // DownloadItem already needs to handle a state in which there is // no associated DownloadFile (history downloads, !IN_PROGRESS downloads) - DownloadItemImpl* download = - CreateDownloadItem(info.get(), bound_net_log); + DownloadItemImpl* download = GetOrCreateDownloadItem(info.get()); scoped_ptr<DownloadFile> download_file( file_factory_->CreateFile( info->save_info.Pass(), default_download_directory, info->url(), info->referrer_url, delegate_->GenerateFileHash(), - stream.Pass(), bound_net_log, + stream.Pass(), download->GetBoundNetLog(), download->DestinationObserverAsWeakPtr())); - download->Start(download_file.Pass()); + scoped_ptr<DownloadRequestHandleInterface> req_handle( + new DownloadRequestHandle(info->request_handle)); + download->Start(download_file.Pass(), req_handle.Pass()); // Delay notification until after Start() so that download_file is bound // to download and all the usual setters (e.g. Cancel) work. @@ -361,154 +411,107 @@ void DownloadManagerImpl::CheckForHistoryFilesRemoval() { for (DownloadMap::iterator it = downloads_.begin(); it != downloads_.end(); ++it) { DownloadItemImpl* item = it->second; - if (item->IsPersisted()) - CheckForFileRemoval(item); + CheckForFileRemoval(item); } } void DownloadManagerImpl::CheckForFileRemoval(DownloadItemImpl* download_item) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (download_item->IsComplete() && - !download_item->GetFileExternallyRemoved()) { - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - base::Bind(&DownloadManagerImpl::CheckForFileRemovalOnFileThread, - this, download_item->GetId(), - download_item->GetTargetFilePath())); - } -} - -void DownloadManagerImpl::CheckForFileRemovalOnFileThread( - int32 download_id, const FilePath& path) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - if (!file_util::PathExists(path)) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&DownloadManagerImpl::OnFileRemovalDetected, - this, - download_id)); + !download_item->GetFileExternallyRemoved() && + delegate_) { + delegate_->CheckForFileExistence( + download_item, + base::Bind(&DownloadManagerImpl::OnFileExistenceChecked, + this, download_item->GetId())); } } -void DownloadManagerImpl::OnFileRemovalDetected(int32 download_id) { +void DownloadManagerImpl::OnFileExistenceChecked(int32 download_id, + bool result) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (ContainsKey(downloads_, download_id)) - downloads_[download_id]->OnDownloadedFileRemoved(); + if (!result) { // File does not exist. + if (ContainsKey(downloads_, download_id)) + downloads_[download_id]->OnDownloadedFileRemoved(); + } } BrowserContext* DownloadManagerImpl::GetBrowserContext() const { return browser_context_; } -DownloadItemImpl* DownloadManagerImpl::CreateDownloadItem( - DownloadCreateInfo* info, const net::BoundNetLog& bound_net_log) { +DownloadItemImpl* DownloadManagerImpl::GetOrCreateDownloadItem( + DownloadCreateInfo* info) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (!info->download_id.IsValid()) info->download_id = GetNextId(); - DownloadItemImpl* download = item_factory_->CreateActiveItem( - this, *info, - scoped_ptr<DownloadRequestHandleInterface>( - new DownloadRequestHandle(info->request_handle)).Pass(), - bound_net_log); - DCHECK(!ContainsKey(downloads_, download->GetId())); - downloads_[download->GetId()] = download; - DCHECK(!ContainsKey(active_downloads_, download->GetId())); - active_downloads_[download->GetId()] = download; + DownloadItemImpl* download = NULL; + if (ContainsKey(downloads_, info->download_id.local())) { + // Resuming an existing download. + download = downloads_[info->download_id.local()]; + DCHECK(download->IsInterrupted()); + } else { + // New download + net::BoundNetLog bound_net_log = + net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD); + download = item_factory_->CreateActiveItem(this, *info, bound_net_log); + downloads_[download->GetId()] = download; + } return download; } DownloadItemImpl* DownloadManagerImpl::CreateSavePackageDownloadItem( - const FilePath& main_file_path, + const base::FilePath& main_file_path, const GURL& page_url, const std::string& mime_type, + scoped_ptr<DownloadRequestHandleInterface> request_handle, DownloadItem::Observer* observer) { net::BoundNetLog bound_net_log = net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD); - DownloadItemImpl* download = item_factory_->CreateSavePageItem( + DownloadItemImpl* download_item = item_factory_->CreateSavePageItem( this, main_file_path, page_url, GetNextId(), mime_type, + request_handle.Pass(), bound_net_log); - download->AddObserver(observer); - - DCHECK(!ContainsKey(downloads_, download->GetId())); - downloads_[download->GetId()] = download; + download_item->AddObserver(observer); + DCHECK(!ContainsKey(downloads_, download_item->GetId())); + downloads_[download_item->GetId()] = download_item; + FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated( + this, download_item)); - FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, download)); - - // Will notify the observer in the callback. - if (delegate_) - delegate_->AddItemToPersistentStore(download); - - return download; -} - -void DownloadManagerImpl::AssertStateConsistent( - DownloadItemImpl* download) const { - CHECK(ContainsKey(downloads_, download->GetId())); - - int64 state = download->GetState(); - base::debug::Alias(&state); - if (ContainsKey(active_downloads_, download->GetId())) { - if (download->IsPersisted()) - CHECK_EQ(DownloadItem::IN_PROGRESS, download->GetState()); - if (DownloadItem::IN_PROGRESS != download->GetState()) - CHECK_EQ(DownloadItem::kUninitializedHandle, download->GetDbHandle()); - } - if (DownloadItem::IN_PROGRESS == download->GetState()) - CHECK(ContainsKey(active_downloads_, download->GetId())); + return download_item; } -void DownloadManagerImpl::DownloadCompleted(DownloadItemImpl* download) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(download); - if (delegate_) - delegate_->UpdateItemInPersistentStore(download); - active_downloads_.erase(download->GetId()); - AssertStateConsistent(download); +void DownloadManagerImpl::OnSavePackageSuccessfullyFinished( + DownloadItem* download_item) { + FOR_EACH_OBSERVER(Observer, observers_, + OnSavePackageSuccessfullyFinished(this, download_item)); } void DownloadManagerImpl::CancelDownload(int32 download_id) { - // A cancel at the right time could remove the download from the - // |active_downloads_| map before we get here. - if (ContainsKey(active_downloads_, download_id)) - active_downloads_[download_id]->Cancel(true); -} - -void DownloadManagerImpl::UpdatePersistence(DownloadItemImpl* download) { - if (delegate_) - delegate_->UpdateItemInPersistentStore(download); -} - -void DownloadManagerImpl::DownloadStopped(DownloadItemImpl* download) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - VLOG(20) << __FUNCTION__ << "()" - << " download = " << download->DebugString(true); - - RemoveFromActiveList(download); - // This function is called from the DownloadItem, so DI state - // should already have been updated. - AssertStateConsistent(download); + DownloadItem* download = GetDownload(download_id); + if (!download || !download->IsInProgress()) + return; + download->Cancel(true); } -void DownloadManagerImpl::RemoveFromActiveList(DownloadItemImpl* download) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(download); - - // Clean up will happen when the history system create callback runs if we - // don't have a valid db_handle yet. - if (download->IsPersisted()) { - active_downloads_.erase(download->GetId()); - if (delegate_) - delegate_->UpdateItemInPersistentStore(download); - } +// Resume a download of a specific URL. We send the request to the +// ResourceDispatcherHost, and let it send us responses like a regular +// download. +void DownloadManagerImpl::ResumeInterruptedDownload( + scoped_ptr<content::DownloadUrlParameters> params, + content::DownloadId id) { + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&BeginDownload, base::Passed(¶ms), id)); } void DownloadManagerImpl::SetDownloadItemFactoryForTesting( @@ -525,63 +528,37 @@ DownloadFileFactory* DownloadManagerImpl::GetDownloadFileFactoryForTesting() { return file_factory_.get(); } -int DownloadManagerImpl::RemoveDownloadItems( - const DownloadItemImplVector& pending_deletes) { - if (pending_deletes.empty()) - return 0; - - // Delete from internal maps. - for (DownloadItemImplVector::const_iterator it = pending_deletes.begin(); - it != pending_deletes.end(); - ++it) { - DownloadItemImpl* download = *it; - DCHECK(download); - int32 download_id = download->GetId(); - delete download; - downloads_.erase(download_id); - } - return static_cast<int>(pending_deletes.size()); -} - void DownloadManagerImpl::DownloadRemoved(DownloadItemImpl* download) { - if (!download || - downloads_.find(download->GetId()) == downloads_.end()) + if (!download) return; - // TODO(benjhayden,rdsmith): Remove this. - if (!download->IsPersisted()) + int32 download_id = download->GetId(); + if (downloads_.find(download_id) == downloads_.end()) return; - // Make history update. - if (delegate_) - delegate_->RemoveItemFromPersistentStore(download); - - // Remove from our tables and delete. - int downloads_count = - RemoveDownloadItems(DownloadItemImplVector(1, download)); - DCHECK_EQ(1, downloads_count); + delete download; + downloads_.erase(download_id); } int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin, base::Time remove_end) { - if (delegate_) - delegate_->RemoveItemsFromPersistentStoreBetween(remove_begin, remove_end); - - DownloadItemImplVector pending_deletes; - for (DownloadMap::const_iterator it = downloads_.begin(); - it != downloads_.end(); - ++it) { + int count = 0; + DownloadMap::const_iterator it = downloads_.begin(); + while (it != downloads_.end()) { DownloadItemImpl* download = it->second; - if (download->IsPersisted() && - download->GetStartTime() >= remove_begin && + + // Increment done here to protect against invalidation below. + ++it; + + if (download->GetStartTime() >= remove_begin && (remove_end.is_null() || download->GetStartTime() < remove_end) && - (download->IsComplete() || download->IsCancelled())) { - AssertStateConsistent(download); - download->NotifyRemoved(); - pending_deletes.push_back(download); + !download->IsInProgress()) { + // Erases the download from downloads_. + download->Remove(); + count++; } } - return RemoveDownloadItems(pending_deletes); + return count; } int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) { @@ -603,7 +580,7 @@ void DownloadManagerImpl::DownloadUrl( DCHECK(params->method() == "POST"); } BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( - &BeginDownload, base::Passed(params.Pass()))); + &BeginDownload, base::Passed(¶ms), DownloadId())); } void DownloadManagerImpl::AddObserver(Observer* observer) { @@ -614,116 +591,47 @@ void DownloadManagerImpl::RemoveObserver(Observer* observer) { observers_.RemoveObserver(observer); } -// Operations posted to us from the history service ---------------------------- - -// The history service has retrieved all download entries. 'entries' contains -// 'DownloadPersistentStoreInfo's in sorted order (by ascending start_time). -void DownloadManagerImpl::OnPersistentStoreQueryComplete( - std::vector<DownloadPersistentStoreInfo>* entries) { - history_size_ = entries->size(); - for (size_t i = 0; i < entries->size(); ++i) { - int64 db_handle = entries->at(i).db_handle; - base::debug::Alias(&db_handle); - - net::BoundNetLog bound_net_log = - net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD); - DownloadItemImpl* download = item_factory_->CreatePersistedItem( - this, GetNextId(), entries->at(i), bound_net_log); - DCHECK(!ContainsKey(downloads_, download->GetId())); - downloads_[download->GetId()] = download; - FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, download)); - VLOG(20) << __FUNCTION__ << "()" << i << ">" - << " download = " << download->DebugString(true); - } - CheckForHistoryFilesRemoval(); -} - -void DownloadManagerImpl::AddDownloadItemToHistory(DownloadItemImpl* download, - int64 db_handle) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK_NE(DownloadItem::kUninitializedHandle, db_handle); - DCHECK(!download->IsPersisted()); - download->SetDbHandle(db_handle); - download->SetIsPersisted(); - - RecordHistorySize(history_size_); - // Not counting |download|. - ++history_size_; - - // Show in the appropriate browser UI. - // This includes buttons to save or cancel, for a dangerous download. - ShowDownloadInBrowser(download); -} - -void DownloadManagerImpl::OnItemAddedToPersistentStore(int32 download_id, - int64 db_handle) { - // It's valid that we don't find a matching item, i.e. on shutdown. - if (!ContainsKey(downloads_, download_id)) - return; - - DownloadItemImpl* item = downloads_[download_id]; - AddDownloadItemToHistory(item, db_handle); - if (item->IsSavePackageDownload()) { - OnSavePageItemAddedToPersistentStore(item); - } else { - OnDownloadItemAddedToPersistentStore(item); - } -} - -// Once the new DownloadItem has been committed to the persistent store, -// associate it with its db_handle (TODO(benjhayden) merge db_handle with id), -// show it in the browser (TODO(benjhayden) the ui should observe us instead), -// and notify observers (TODO(benjhayden) observers should be able to see the -// item when it's created so they can observe it directly. Are there any -// clients that actually need to know when the item is added to the history?). -void DownloadManagerImpl::OnDownloadItemAddedToPersistentStore( - DownloadItemImpl* item) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << item->GetDbHandle() - << " download_id = " << item->GetId() - << " download = " << item->DebugString(true); - - // If the download is still in progress, try to complete it. - // - // Otherwise, download has been cancelled or interrupted before we've - // received the DB handle. We post one final message to the history - // service so that it can be properly in sync with the DownloadItem's - // completion status, and also inform any observers so that they get - // more than just the start notification. - if (item->IsInProgress()) { - item->MaybeCompleteDownload(); - } else { - DCHECK(item->IsCancelled()); - active_downloads_.erase(item->GetId()); - if (delegate_) - delegate_->UpdateItemInPersistentStore(item); - item->UpdateObservers(); - } -} - -void DownloadManagerImpl::ShowDownloadInBrowser(DownloadItemImpl* download) { - // The 'contents' may no longer exist if the user closed the contents before - // we get this start completion event. - WebContents* content = download->GetWebContents(); - - // If the contents no longer exists, we ask the embedder to suggest another - // contents. - if (!content && delegate_) - content = delegate_->GetAlternativeWebContentsToNotifyForDownload(); - - if (content && content->GetDelegate()) - content->GetDelegate()->OnStartDownload(content, download); +DownloadItem* DownloadManagerImpl::CreateDownloadItem( + const base::FilePath& current_path, + const base::FilePath& target_path, + const std::vector<GURL>& url_chain, + const GURL& referrer_url, + const base::Time& start_time, + const base::Time& end_time, + int64 received_bytes, + int64 total_bytes, + DownloadItem::DownloadState state, + DownloadDangerType danger_type, + DownloadInterruptReason interrupt_reason, + bool opened) { + DownloadItemImpl* item = item_factory_->CreatePersistedItem( + this, + GetNextId(), + current_path, + target_path, + url_chain, + referrer_url, + start_time, + end_time, + received_bytes, + total_bytes, + state, + danger_type, + interrupt_reason, + opened, + net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD)); + DCHECK(!ContainsKey(downloads_, item->GetId())); + downloads_[item->GetId()] = item; + FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, item)); + VLOG(20) << __FUNCTION__ << "() download = " << item->DebugString(true); + return item; } int DownloadManagerImpl::InProgressCount() const { - // Don't use active_downloads_.count() because Cancel() leaves items in - // active_downloads_ if they haven't made it into the persistent store yet. - // Need to actually look at each item's state. int count = 0; - for (DownloadMap::const_iterator it = active_downloads_.begin(); - it != active_downloads_.end(); ++it) { - DownloadItemImpl* item = it->second; - if (item->IsInProgress()) + for (DownloadMap::const_iterator it = downloads_.begin(); + it != downloads_.end(); ++it) { + if (it->second->IsInProgress()) ++count; } return count; @@ -740,73 +648,7 @@ void DownloadManagerImpl::GetAllDownloads(DownloadVector* downloads) { } } -// Confirm that everything in all maps is also in |downloads_|, and that -// everything in |downloads_| is also in some other map. -void DownloadManagerImpl::AssertContainersConsistent() const { -#if !defined(NDEBUG) - // Turn everything into sets. - const DownloadMap* input_maps[] = {&active_downloads_}; - DownloadSet active_set; - DownloadSet* all_sets[] = {&active_set}; - DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets)); - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) { - for (DownloadMap::const_iterator it = input_maps[i]->begin(); - it != input_maps[i]->end(); ++it) { - all_sets[i]->insert(&*it->second); - } - } - - DownloadSet all_downloads; - for (DownloadMap::const_iterator it = downloads_.begin(); - it != downloads_.end(); ++it) { - all_downloads.insert(it->second); - } - - // Check if each set is fully present in downloads, and create a union. - for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) { - DownloadSet remainder; - std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin()); - std::set_difference(all_sets[i]->begin(), all_sets[i]->end(), - all_downloads.begin(), all_downloads.end(), - insert_it); - DCHECK(remainder.empty()); - } -#endif -} - -// SavePackage will call SavePageDownloadFinished upon completion/cancellation. -// The history callback will call OnSavePageItemAddedToPersistentStore. -// If the download finishes before the history callback, -// OnSavePageItemAddedToPersistentStore calls SavePageDownloadFinished, ensuring -// that the history event is update regardless of the order in which these two -// events complete. -// If something removes the download item from the download manager (Remove, -// Shutdown) the result will be that the SavePage system will not be able to -// properly update the download item (which no longer exists) or the download -// history, but the action will complete properly anyway. This may lead to the -// history entry being wrong on a reload of chrome (specifically in the case of -// Initiation -> History Callback -> Removal -> Completion), but there's no way -// to solve that without canceling on Remove (which would then update the DB). - -void DownloadManagerImpl::OnSavePageItemAddedToPersistentStore( - DownloadItemImpl* item) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // Finalize this download if it finished before the history callback. - if (!item->IsInProgress()) - SavePageDownloadFinished(item); -} - -void DownloadManagerImpl::SavePageDownloadFinished(DownloadItem* download) { - if (download->IsPersisted()) { - if (delegate_) - delegate_->UpdateItemInPersistentStore(download); - } -} - -void DownloadManagerImpl::DownloadOpened(DownloadItemImpl* download) { - if (delegate_) - delegate_->UpdateItemInPersistentStore(download); +void DownloadManagerImpl::OpenDownload(DownloadItemImpl* download) { int num_unopened = 0; for (DownloadMap::iterator it = downloads_.begin(); it != downloads_.end(); ++it) { @@ -816,31 +658,14 @@ void DownloadManagerImpl::DownloadOpened(DownloadItemImpl* download) { ++num_unopened; } RecordOpensOutstanding(num_unopened); -} -void DownloadManagerImpl::DownloadRenamedToIntermediateName( - DownloadItemImpl* download) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // download->GetFullPath() is only expected to be meaningful after this - // callback is received. Therefore we can now add the download to a persistent - // store. If the rename failed, we processed an interrupt - // before we receive the DownloadRenamedToIntermediateName() call. - if (delegate_) { - delegate_->AddItemToPersistentStore(download); - } else { - OnItemAddedToPersistentStore(download->GetId(), - DownloadItem::kUninitializedHandle); - } + if (delegate_) + delegate_->OpenDownload(download); } -void DownloadManagerImpl::DownloadRenamedToFinalName( - DownloadItemImpl* download) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // If the rename failed, we processed an interrupt before we get here. - if (delegate_) { - delegate_->UpdatePathForItemInPersistentStore( - download, download->GetFullPath()); - } +void DownloadManagerImpl::ShowDownloadInShell(DownloadItemImpl* download) { + if (delegate_) + delegate_->ShowDownloadInShell(download); } } // namespace content |