1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/network/upload_progress_tracker.h"
6
7 #include "base/logging.h"
8 #include "net/base/upload_progress.h"
9 #include "net/url_request/url_request.h"
10
11 namespace network {
12 namespace {
13 // The interval for calls to ReportUploadProgress.
14 constexpr base::TimeDelta kUploadProgressInterval =
15 base::TimeDelta::FromMilliseconds(100);
16 } // namespace
17
UploadProgressTracker(const base::Location & location,UploadProgressReportCallback report_progress,net::URLRequest * request,scoped_refptr<base::SequencedTaskRunner> task_runner)18 UploadProgressTracker::UploadProgressTracker(
19 const base::Location& location,
20 UploadProgressReportCallback report_progress,
21 net::URLRequest* request,
22 scoped_refptr<base::SequencedTaskRunner> task_runner)
23 : request_(request), report_progress_(std::move(report_progress)) {
24 DCHECK(report_progress_);
25
26 progress_timer_.SetTaskRunner(std::move(task_runner));
27 progress_timer_.Start(location, kUploadProgressInterval, this,
28 &UploadProgressTracker::ReportUploadProgressIfNeeded);
29 }
30
~UploadProgressTracker()31 UploadProgressTracker::~UploadProgressTracker() {}
32
OnAckReceived()33 void UploadProgressTracker::OnAckReceived() {
34 waiting_for_upload_progress_ack_ = false;
35 }
36
OnUploadCompleted()37 void UploadProgressTracker::OnUploadCompleted() {
38 waiting_for_upload_progress_ack_ = false;
39 ReportUploadProgressIfNeeded();
40 progress_timer_.Stop();
41 }
42
43 // static
GetUploadProgressIntervalForTesting()44 base::TimeDelta UploadProgressTracker::GetUploadProgressIntervalForTesting() {
45 return kUploadProgressInterval;
46 }
47
GetCurrentTime() const48 base::TimeTicks UploadProgressTracker::GetCurrentTime() const {
49 return base::TimeTicks::Now();
50 }
51
GetUploadProgress() const52 net::UploadProgress UploadProgressTracker::GetUploadProgress() const {
53 return request_->GetUploadProgress();
54 }
55
ReportUploadProgressIfNeeded()56 void UploadProgressTracker::ReportUploadProgressIfNeeded() {
57 if (waiting_for_upload_progress_ack_)
58 return;
59
60 net::UploadProgress progress = GetUploadProgress();
61 if (!progress.size())
62 return; // Nothing to upload, or in the chunked upload mode.
63
64 // No progress made since last time, or the progress was reset by a redirect
65 // or a retry.
66 if (progress.position() <= last_upload_position_)
67 return;
68
69 const uint64_t kHalfPercentIncrements = 200;
70 const base::TimeDelta kOneSecond = base::TimeDelta::FromMilliseconds(1000);
71
72 uint64_t amt_since_last = progress.position() - last_upload_position_;
73 base::TimeTicks now = GetCurrentTime();
74 base::TimeDelta time_since_last = now - last_upload_ticks_;
75
76 bool is_finished = (progress.size() == progress.position());
77 bool enough_new_progress =
78 (amt_since_last > (progress.size() / kHalfPercentIncrements));
79 bool too_much_time_passed = time_since_last > kOneSecond;
80
81 if (is_finished || enough_new_progress || too_much_time_passed) {
82 report_progress_.Run(progress);
83 waiting_for_upload_progress_ack_ = true;
84 last_upload_ticks_ = now;
85 last_upload_position_ = progress.position();
86 }
87 }
88
89 } // namespace network
90