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