blob: ad1eca6a8399228ebe1d68eb7683749da95077d5 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/upload_progress_tracker.h"
#include "base/check.h"
#include "net/base/upload_progress.h"
#include "net/url_request/url_request.h"
namespace network {
namespace {
// The interval for calls to ReportUploadProgress.
constexpr base::TimeDelta kUploadProgressInterval =
base::TimeDelta::FromMilliseconds(100);
} // namespace
UploadProgressTracker::UploadProgressTracker(
const base::Location& location,
UploadProgressReportCallback report_progress,
net::URLRequest* request,
scoped_refptr<base::SequencedTaskRunner> task_runner)
: request_(request), report_progress_(std::move(report_progress)) {
DCHECK(report_progress_);
progress_timer_.SetTaskRunner(std::move(task_runner));
progress_timer_.Start(location, kUploadProgressInterval, this,
&UploadProgressTracker::ReportUploadProgressIfNeeded);
}
UploadProgressTracker::~UploadProgressTracker() {}
void UploadProgressTracker::OnAckReceived() {
waiting_for_upload_progress_ack_ = false;
}
void UploadProgressTracker::OnUploadCompleted() {
waiting_for_upload_progress_ack_ = false;
ReportUploadProgressIfNeeded();
progress_timer_.Stop();
}
// static
base::TimeDelta UploadProgressTracker::GetUploadProgressIntervalForTesting() {
return kUploadProgressInterval;
}
base::TimeTicks UploadProgressTracker::GetCurrentTime() const {
return base::TimeTicks::Now();
}
net::UploadProgress UploadProgressTracker::GetUploadProgress() const {
return request_->GetUploadProgress();
}
void UploadProgressTracker::ReportUploadProgressIfNeeded() {
if (waiting_for_upload_progress_ack_)
return;
net::UploadProgress progress = GetUploadProgress();
if (!progress.size())
return; // Nothing to upload, or in the chunked upload mode.
// No progress made since last time, or the progress was reset by a redirect
// or a retry.
if (progress.position() <= last_upload_position_)
return;
const uint64_t kHalfPercentIncrements = 200;
const base::TimeDelta kOneSecond = base::TimeDelta::FromMilliseconds(1000);
uint64_t amt_since_last = progress.position() - last_upload_position_;
base::TimeTicks now = GetCurrentTime();
base::TimeDelta time_since_last = now - last_upload_ticks_;
bool is_finished = (progress.size() == progress.position());
bool enough_new_progress =
(amt_since_last > (progress.size() / kHalfPercentIncrements));
bool too_much_time_passed = time_since_last > kOneSecond;
if (is_finished || enough_new_progress || too_much_time_passed) {
report_progress_.Run(progress);
waiting_for_upload_progress_ack_ = true;
last_upload_ticks_ = now;
last_upload_position_ = progress.position();
}
}
} // namespace network