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"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/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"
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)
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// These constants control the default retry behavior for failing renames. Each
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// retry is performed after a delay that is twice the previous delay. The
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// initial delay is specified by kInitialRenameRetryDelayMs.
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int kMaxRenameRetries = 3;
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int kInitialRenameRetryDelayMs = 200;
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DownloadFile::number_active_objects_ = 0;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadFileImpl::DownloadFileImpl(
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<DownloadSaveInfo> save_info,
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& default_download_directory,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& referrer_url,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool calculate_hash,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<ByteStreamReader> stream,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::BoundNetLog& bound_net_log,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::WeakPtr<DownloadDestinationObserver> observer)
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : file_(save_info->file_path,
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            url,
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            referrer_url,
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            save_info->offset,
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            calculate_hash,
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            save_info->hash_state,
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            save_info->file.Pass(),
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            bound_net_log),
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      default_download_directory_(default_download_directory),
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      stream_reader_(stream.Pass()),
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      bytes_seen_(0),
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      bound_net_log_(bound_net_log),
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      observer_(observer),
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_factory_(this) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadFileImpl::~DownloadFileImpl() {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --number_active_objects_;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::Initialize(const InitializeCallback& callback) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  update_timer_.reset(new base::RepeatingTimer<DownloadFileImpl>());
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadInterruptReason result =
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_.Initialize(default_download_directory_);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream_reader_->RegisterCallback(
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&DownloadFileImpl::StreamActive, weak_factory_.GetWeakPtr()));
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_start_ = base::TimeTicks::Now();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Primarily to make reset to zero in restart visible to owner.
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SendUpdate();
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initial pull from the straw.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StreamActive();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE, base::Bind(
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          callback, DOWNLOAD_INTERRUPT_REASON_NONE));
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++number_active_objects_;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadInterruptReason DownloadFileImpl::AppendDataToFile(
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* data, size_t data_len) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!update_timer_->IsRunning()) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    update_timer_->Start(FROM_HERE,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         this, &DownloadFileImpl::SendUpdate);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  rate_estimator_.Increment(data_len);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.AppendDataToFile(data, data_len);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::RenameAndUniquify(
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& full_path,
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const RenameCompletionCallback& callback) {
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  RenameWithRetryInternal(
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      full_path, UNIQUIFY, kMaxRenameRetries, base::TimeTicks(), callback);
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid DownloadFileImpl::RenameAndAnnotate(
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::FilePath& full_path,
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const RenameCompletionCallback& callback) {
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  RenameWithRetryInternal(full_path,
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          ANNOTATE_WITH_SOURCE_INFORMATION,
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          kMaxRenameRetries,
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          base::TimeTicks(),
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          callback);
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibase::TimeDelta DownloadFileImpl::GetRetryDelayForFailedRename(
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int attempt_number) {
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_GE(attempt_number, 0);
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // |delay| starts at kInitialRenameRetryDelayMs and increases by a factor of
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // 2 at each subsequent retry. Assumes that |retries_left| starts at
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // kMaxRenameRetries. Also assumes that kMaxRenameRetries is less than the
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // number of bits in an int.
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return base::TimeDelta::FromMilliseconds(kInitialRenameRetryDelayMs) *
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         (1 << attempt_number);
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool DownloadFileImpl::ShouldRetryFailedRename(DownloadInterruptReason reason) {
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return reason == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid DownloadFileImpl::RenameWithRetryInternal(
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& full_path,
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    RenameOption option,
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int retries_left,
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::TimeTicks time_of_first_failure,
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const RenameCompletionCallback& callback) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath new_path(full_path);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if ((option & UNIQUIFY) && full_path != file_.full_path()) {
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int uniquifier =
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::GetUniquePathNumber(new_path, base::FilePath::StringType());
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (uniquifier > 0)
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new_path = new_path.InsertBeforeExtensionASCII(
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          base::StringPrintf(" (%d)", uniquifier));
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DownloadInterruptReason reason = file_.Rename(new_path);
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Attempt to retry the rename if possible. If the rename failed and the
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // subsequent open also failed, then in_progress() would be false. We don't
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // try to retry renames if the in_progress() was false to begin with since we
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // have less assurance that the file at file_.full_path() was the one we were
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // working with.
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (ShouldRetryFailedRename(reason) && file_.in_progress() &&
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      retries_left > 0) {
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int attempt_number = kMaxRenameRetries - retries_left;
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    BrowserThread::PostDelayedTask(
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        BrowserThread::FILE,
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        FROM_HERE,
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::Bind(&DownloadFileImpl::RenameWithRetryInternal,
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   weak_factory_.GetWeakPtr(),
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   full_path,
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   option,
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   --retries_left,
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   time_of_first_failure.is_null() ? base::TimeTicks::Now()
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                   : time_of_first_failure,
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   callback),
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        GetRetryDelayForFailedRename(attempt_number));
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!time_of_first_failure.is_null())
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    RecordDownloadFileRenameResultAfterRetry(
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::TimeTicks::Now() - time_of_first_failure, reason);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (reason == DOWNLOAD_INTERRUPT_REASON_NONE &&
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      (option & ANNOTATE_WITH_SOURCE_INFORMATION)) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Doing the annotation after the rename rather than before leaves
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a very small window during which the file has the final name but
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // hasn't been marked with the Mark Of The Web.  However, it allows
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // anti-virus scanners on Windows to actually see the data
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // (http://crbug.com/127999) under the correct name (which is information
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // it uses).
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reason = file_.AnnotateWithSourceInformation();
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure our information is updated, since we're about to
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // error out.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendUpdate();
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Null out callback so that we don't do any more stream processing.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_reader_->RegisterCallback(base::Closure());
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_path.clear();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(callback, reason, new_path));
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::Detach() {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_.Detach();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::Cancel() {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_.Cancel();
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath DownloadFileImpl::FullPath() const {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.full_path();
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadFileImpl::InProgress() const {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.in_progress();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 DownloadFileImpl::CurrentSpeed() const {
232868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return rate_estimator_.GetCountPerSecond();
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadFileImpl::GetHash(std::string* hash) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.GetHash(hash);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string DownloadFileImpl::GetHashState() {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_.GetHashState();
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
243ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid DownloadFileImpl::SetClientGuid(const std::string& guid) {
244ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  file_.SetClientGuid(guid);
245ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
246ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::StreamActive() {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks start(base::TimeTicks::Now());
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks now;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<net::IOBuffer> incoming_data;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t incoming_data_size = 0;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t total_incoming_data_size = 0;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t num_buffers = 0;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ByteStreamReader::StreamState state(ByteStreamReader::STREAM_EMPTY);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta delta(
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kMaxTimeBlockingFileThreadMs));
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Take care of any file local activity required.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state = stream_reader_->Read(&incoming_data, &incoming_data_size);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (state) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ByteStreamReader::STREAM_EMPTY:
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ByteStreamReader::STREAM_HAS_DATA:
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ++num_buffers;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeTicks write_start(base::TimeTicks::Now());
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          reason = AppendDataToFile(
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              incoming_data.get()->data(), incoming_data_size);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          disk_writes_time_ += (base::TimeTicks::Now() - write_start);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bytes_seen_ += incoming_data_size;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          total_incoming_data_size += incoming_data_size;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ByteStreamReader::STREAM_COMPLETE:
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
279a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          reason = static_cast<DownloadInterruptReason>(
280a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)              stream_reader_->GetStatus());
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SendUpdate();
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeTicks close_start(base::TimeTicks::Now());
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          file_.Finish();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeTicks now(base::TimeTicks::Now());
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          disk_writes_time_ += (now - close_start);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          RecordFileBandwidth(
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              bytes_seen_, disk_writes_time_, now - download_start_);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          update_timer_.reset();
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    now = base::TimeTicks::Now();
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (state == ByteStreamReader::STREAM_HAS_DATA &&
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           reason == DOWNLOAD_INTERRUPT_REASON_NONE &&
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           now - start <= delta);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're stopping to yield the thread, post a task so we come back.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state == ByteStreamReader::STREAM_HAS_DATA &&
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      now - start > delta) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::FILE, FROM_HERE,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&DownloadFileImpl::StreamActive,
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   weak_factory_.GetWeakPtr()));
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (total_incoming_data_size)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordFileThreadReceiveBuffers(num_buffers);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordContiguousWriteTime(now - start);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Take care of communication with our observer.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Error case for both upstream source and file write.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Shut down processing and signal an error to our observer.
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Our observer will clean us up.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_reader_->RegisterCallback(base::Closure());
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    weak_factory_.InvalidateWeakPtrs();
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendUpdate();                       // Make info up to date before error.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE,
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&DownloadDestinationObserver::DestinationError,
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   observer_, reason));
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (state == ByteStreamReader::STREAM_COMPLETE) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Signal successful completion and shut down processing.
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_reader_->RegisterCallback(base::Closure());
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    weak_factory_.InvalidateWeakPtrs();
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string hash;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetHash(&hash) || file_.IsEmptyHash(hash))
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hash.clear();
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendUpdate();
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE,
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            &DownloadDestinationObserver::DestinationCompleted,
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            observer_, hash));
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (bound_net_log_.IsLogging()) {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bound_net_log_.AddEvent(
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        net::NetLog::TYPE_DOWNLOAD_STREAM_DRAINED,
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&FileStreamDrainedNetLogCallback, total_incoming_data_size,
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   num_buffers));
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadFileImpl::SendUpdate() {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&DownloadDestinationObserver::DestinationUpdate,
352a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                 observer_, file_.bytes_so_far(), CurrentSpeed(),
353a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                 GetHashState()));
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DownloadFile::GetNumberOfDownloadFiles() {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return number_active_objects_;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
362