download_file_impl.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_file_impl.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop_proxy.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/byte_stream.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_create_info.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_interrupt_reasons_impl.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_net_log_parameters.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/download/download_stats.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_destination_observer.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/power_save_blocker.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kUpdatePeriodMs = 500;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxTimeBlockingFileThreadMs = 1000;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DownloadFile::number_active_objects_ = 0;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadFileImpl::DownloadFileImpl(
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<DownloadSaveInfo> save_info,
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& default_download_directory,
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& referrer_url,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool calculate_hash,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<ByteStreamReader> stream,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::BoundNetLog& bound_net_log,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<PowerSaveBlocker> power_save_blocker,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::WeakPtr<DownloadDestinationObserver> observer)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        : file_(save_info->file_path,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                url,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                referrer_url,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                save_info->offset,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                calculate_hash,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                save_info->hash_state,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                save_info->file_stream.Pass(),
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                bound_net_log),
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          default_download_directory_(default_download_directory),
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          stream_reader_(stream.Pass()),
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bytes_seen_(0),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bound_net_log_(bound_net_log),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          observer_(observer),
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          weak_factory_(this),
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          power_save_blocker_(power_save_blocker.Pass()) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadFileImpl::~DownloadFileImpl() {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --number_active_objects_;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::Initialize(const InitializeCallback& callback) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  update_timer_.reset(new base::RepeatingTimer<DownloadFileImpl>());
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadInterruptReason result =
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_.Initialize(default_download_directory_);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream_reader_->RegisterCallback(
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&DownloadFileImpl::StreamActive, weak_factory_.GetWeakPtr()));
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_start_ = base::TimeTicks::Now();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Primarily to make reset to zero in restart visible to owner.
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SendUpdate();
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initial pull from the straw.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StreamActive();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE, base::Bind(
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          callback, DOWNLOAD_INTERRUPT_REASON_NONE));
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++number_active_objects_;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadInterruptReason DownloadFileImpl::AppendDataToFile(
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* data, size_t data_len) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!update_timer_->IsRunning()) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    update_timer_->Start(FROM_HERE,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         this, &DownloadFileImpl::SendUpdate);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.AppendDataToFile(data, data_len);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::RenameAndUniquify(
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& full_path,
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const RenameCompletionCallback& callback) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath new_path(full_path);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int uniquifier = file_util::GetUniquePathNumber(
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new_path, base::FilePath::StringType());
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (uniquifier > 0) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_path = new_path.InsertBeforeExtensionASCII(
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringPrintf(" (%d)", uniquifier));
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadInterruptReason reason = file_.Rename(new_path);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure our information is updated, since we're about to
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error out.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendUpdate();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Null out callback so that we don't do any more stream processing.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_reader_->RegisterCallback(base::Closure());
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_path.clear();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(callback, reason, new_path));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::RenameAndAnnotate(
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& full_path,
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const RenameCompletionCallback& callback) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath new_path(full_path);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Short circuit null rename.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (full_path != file_.full_path())
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reason = file_.Rename(new_path);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Doing the annotation after the rename rather than before leaves
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a very small window during which the file has the final name but
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // hasn't been marked with the Mark Of The Web.  However, it allows
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // anti-virus scanners on Windows to actually see the data
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // (http://crbug.com/127999) under the correct name (which is information
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // it uses).
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reason = file_.AnnotateWithSourceInformation();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure our information is updated, since we're about to
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error out.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendUpdate();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Null out callback so that we don't do any more stream processing.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_reader_->RegisterCallback(base::Closure());
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_path.clear();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(callback, reason, new_path));
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::Detach() {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_.Detach();
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::Cancel() {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_.Cancel();
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath DownloadFileImpl::FullPath() const {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.full_path();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadFileImpl::InProgress() const {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.in_progress();
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 DownloadFileImpl::CurrentSpeed() const {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.CurrentSpeed();
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadFileImpl::GetHash(std::string* hash) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.GetHash(hash);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string DownloadFileImpl::GetHashState() {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.GetHashState();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::StreamActive() {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks start(base::TimeTicks::Now());
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks now;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<net::IOBuffer> incoming_data;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t incoming_data_size = 0;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t total_incoming_data_size = 0;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t num_buffers = 0;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ByteStreamReader::StreamState state(ByteStreamReader::STREAM_EMPTY);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta delta(
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kMaxTimeBlockingFileThreadMs));
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Take care of any file local activity required.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state = stream_reader_->Read(&incoming_data, &incoming_data_size);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (state) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ByteStreamReader::STREAM_EMPTY:
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ByteStreamReader::STREAM_HAS_DATA:
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ++num_buffers;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeTicks write_start(base::TimeTicks::Now());
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          reason = AppendDataToFile(
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              incoming_data.get()->data(), incoming_data_size);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          disk_writes_time_ += (base::TimeTicks::Now() - write_start);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bytes_seen_ += incoming_data_size;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          total_incoming_data_size += incoming_data_size;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ByteStreamReader::STREAM_COMPLETE:
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          reason = stream_reader_->GetStatus();
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SendUpdate();
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeTicks close_start(base::TimeTicks::Now());
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          file_.Finish();
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeTicks now(base::TimeTicks::Now());
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          disk_writes_time_ += (now - close_start);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          RecordFileBandwidth(
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              bytes_seen_, disk_writes_time_, now - download_start_);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          update_timer_.reset();
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    now = base::TimeTicks::Now();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (state == ByteStreamReader::STREAM_HAS_DATA &&
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           reason == DOWNLOAD_INTERRUPT_REASON_NONE &&
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           now - start <= delta);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're stopping to yield the thread, post a task so we come back.
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state == ByteStreamReader::STREAM_HAS_DATA &&
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      now - start > delta) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::FILE, FROM_HERE,
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&DownloadFileImpl::StreamActive,
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   weak_factory_.GetWeakPtr()));
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (total_incoming_data_size)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordFileThreadReceiveBuffers(num_buffers);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordContiguousWriteTime(now - start);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Take care of communication with our observer.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Error case for both upstream source and file write.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Shut down processing and signal an error to our observer.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Our observer will clean us up.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_reader_->RegisterCallback(base::Closure());
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    weak_factory_.InvalidateWeakPtrs();
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendUpdate();                       // Make info up to date before error.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE,
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&DownloadDestinationObserver::DestinationError,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   observer_, reason));
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (state == ByteStreamReader::STREAM_COMPLETE) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Signal successful completion and shut down processing.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_reader_->RegisterCallback(base::Closure());
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    weak_factory_.InvalidateWeakPtrs();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string hash;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetHash(&hash) || file_.IsEmptyHash(hash))
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hash.clear();
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendUpdate();
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            &DownloadDestinationObserver::DestinationCompleted,
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            observer_, hash));
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bound_net_log_.IsLoggingAllEvents()) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bound_net_log_.AddEvent(
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        net::NetLog::TYPE_DOWNLOAD_STREAM_DRAINED,
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&FileStreamDrainedNetLogCallback, total_incoming_data_size,
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   num_buffers));
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::SendUpdate() {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&DownloadDestinationObserver::DestinationUpdate,
305a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                 observer_, file_.bytes_so_far(), CurrentSpeed(),
306a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                 GetHashState()));
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DownloadFile::GetNumberOfDownloadFiles() {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return number_active_objects_;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
315