download_file_impl.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/strings/stringprintf.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/byte_stream.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_create_info.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_interrupt_reasons_impl.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_net_log_parameters.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/download/download_stats.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_destination_observer.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/power_save_blocker.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kUpdatePeriodMs = 500;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxTimeBlockingFileThreadMs = 1000;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DownloadFile::number_active_objects_ = 0;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadFileImpl::DownloadFileImpl(
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<DownloadSaveInfo> save_info,
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& default_download_directory,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& referrer_url,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool calculate_hash,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<ByteStreamReader> stream,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::BoundNetLog& bound_net_log,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<PowerSaveBlocker> power_save_blocker,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::WeakPtr<DownloadDestinationObserver> observer)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        : file_(save_info->file_path,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                url,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                referrer_url,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                save_info->offset,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                calculate_hash,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                save_info->hash_state,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                save_info->file_stream.Pass(),
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                bound_net_log),
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          default_download_directory_(default_download_directory),
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          stream_reader_(stream.Pass()),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bytes_seen_(0),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bound_net_log_(bound_net_log),
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          observer_(observer),
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          weak_factory_(this),
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          power_save_blocker_(power_save_blocker.Pass()) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadFileImpl::~DownloadFileImpl() {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --number_active_objects_;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::Initialize(const InitializeCallback& callback) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  update_timer_.reset(new base::RepeatingTimer<DownloadFileImpl>());
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadInterruptReason result =
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_.Initialize(default_download_directory_);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream_reader_->RegisterCallback(
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&DownloadFileImpl::StreamActive, weak_factory_.GetWeakPtr()));
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_start_ = base::TimeTicks::Now();
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Primarily to make reset to zero in restart visible to owner.
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SendUpdate();
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initial pull from the straw.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StreamActive();
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE, base::Bind(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          callback, DOWNLOAD_INTERRUPT_REASON_NONE));
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++number_active_objects_;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadInterruptReason DownloadFileImpl::AppendDataToFile(
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* data, size_t data_len) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!update_timer_->IsRunning()) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    update_timer_->Start(FROM_HERE,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         this, &DownloadFileImpl::SendUpdate);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  rate_estimator_.Increment(data_len);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.AppendDataToFile(data, data_len);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::RenameAndUniquify(
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& full_path,
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const RenameCompletionCallback& callback) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath new_path(full_path);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int uniquifier = base::GetUniquePathNumber(
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new_path, base::FilePath::StringType());
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (uniquifier > 0) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_path = new_path.InsertBeforeExtensionASCII(
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringPrintf(" (%d)", uniquifier));
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadInterruptReason reason = file_.Rename(new_path);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure our information is updated, since we're about to
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error out.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendUpdate();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Null out callback so that we don't do any more stream processing.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_reader_->RegisterCallback(base::Closure());
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_path.clear();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(callback, reason, new_path));
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::RenameAndAnnotate(
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& full_path,
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const RenameCompletionCallback& callback) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath new_path(full_path);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Short circuit null rename.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (full_path != file_.full_path())
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reason = file_.Rename(new_path);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Doing the annotation after the rename rather than before leaves
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a very small window during which the file has the final name but
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // hasn't been marked with the Mark Of The Web.  However, it allows
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // anti-virus scanners on Windows to actually see the data
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // (http://crbug.com/127999) under the correct name (which is information
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // it uses).
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reason = file_.AnnotateWithSourceInformation();
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure our information is updated, since we're about to
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error out.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendUpdate();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Null out callback so that we don't do any more stream processing.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_reader_->RegisterCallback(base::Closure());
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_path.clear();
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(callback, reason, new_path));
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::Detach() {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_.Detach();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::Cancel() {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_.Cancel();
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath DownloadFileImpl::FullPath() const {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.full_path();
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadFileImpl::InProgress() const {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.in_progress();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 DownloadFileImpl::CurrentSpeed() const {
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return rate_estimator_.GetCountPerSecond();
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadFileImpl::GetHash(std::string* hash) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.GetHash(hash);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string DownloadFileImpl::GetHashState() {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.GetHashState();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
203ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid DownloadFileImpl::SetClientGuid(const std::string& guid) {
204ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  file_.SetClientGuid(guid);
205ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
206ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::StreamActive() {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks start(base::TimeTicks::Now());
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks now;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<net::IOBuffer> incoming_data;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t incoming_data_size = 0;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t total_incoming_data_size = 0;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t num_buffers = 0;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ByteStreamReader::StreamState state(ByteStreamReader::STREAM_EMPTY);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta delta(
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kMaxTimeBlockingFileThreadMs));
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Take care of any file local activity required.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state = stream_reader_->Read(&incoming_data, &incoming_data_size);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (state) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ByteStreamReader::STREAM_EMPTY:
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ByteStreamReader::STREAM_HAS_DATA:
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ++num_buffers;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeTicks write_start(base::TimeTicks::Now());
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          reason = AppendDataToFile(
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              incoming_data.get()->data(), incoming_data_size);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          disk_writes_time_ += (base::TimeTicks::Now() - write_start);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bytes_seen_ += incoming_data_size;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          total_incoming_data_size += incoming_data_size;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ByteStreamReader::STREAM_COMPLETE:
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
239a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          reason = static_cast<DownloadInterruptReason>(
240a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)              stream_reader_->GetStatus());
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SendUpdate();
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeTicks close_start(base::TimeTicks::Now());
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          file_.Finish();
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeTicks now(base::TimeTicks::Now());
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          disk_writes_time_ += (now - close_start);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          RecordFileBandwidth(
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              bytes_seen_, disk_writes_time_, now - download_start_);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          update_timer_.reset();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    now = base::TimeTicks::Now();
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (state == ByteStreamReader::STREAM_HAS_DATA &&
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           reason == DOWNLOAD_INTERRUPT_REASON_NONE &&
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           now - start <= delta);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're stopping to yield the thread, post a task so we come back.
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state == ByteStreamReader::STREAM_HAS_DATA &&
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      now - start > delta) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::FILE, FROM_HERE,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&DownloadFileImpl::StreamActive,
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   weak_factory_.GetWeakPtr()));
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (total_incoming_data_size)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordFileThreadReceiveBuffers(num_buffers);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordContiguousWriteTime(now - start);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Take care of communication with our observer.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Error case for both upstream source and file write.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Shut down processing and signal an error to our observer.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Our observer will clean us up.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_reader_->RegisterCallback(base::Closure());
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    weak_factory_.InvalidateWeakPtrs();
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendUpdate();                       // Make info up to date before error.
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE,
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&DownloadDestinationObserver::DestinationError,
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   observer_, reason));
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (state == ByteStreamReader::STREAM_COMPLETE) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Signal successful completion and shut down processing.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_reader_->RegisterCallback(base::Closure());
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    weak_factory_.InvalidateWeakPtrs();
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string hash;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetHash(&hash) || file_.IsEmptyHash(hash))
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hash.clear();
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendUpdate();
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE,
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            &DownloadDestinationObserver::DestinationCompleted,
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            observer_, hash));
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (bound_net_log_.IsLogging()) {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bound_net_log_.AddEvent(
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        net::NetLog::TYPE_DOWNLOAD_STREAM_DRAINED,
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&FileStreamDrainedNetLogCallback, total_incoming_data_size,
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   num_buffers));
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::SendUpdate() {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&DownloadDestinationObserver::DestinationUpdate,
312a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                 observer_, file_.bytes_so_far(), CurrentSpeed(),
313a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                 GetHashState()));
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DownloadFile::GetNumberOfDownloadFiles() {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return number_active_objects_;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
322