blob: 2a65462e551d578d618723160ba2fa0781a05d06 [file] [log] [blame]
johnme6727a62a2015-05-07 13:48:301// Copyright 2015 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 "net/base/backoff_entry_serializer.h"
6
Daniel McArdle5aea4642020-08-05 16:59:547#include <algorithm>
dchengc7eeda422015-12-26 03:56:488#include <utility>
9
Dan McArdle1b605dc2021-09-23 17:54:3110#include "base/notreached.h"
johnme6727a62a2015-05-07 13:48:3011#include "base/strings/string_number_conversions.h"
12#include "base/time/tick_clock.h"
13#include "base/values.h"
14#include "net/base/backoff_entry.h"
15
16namespace {
Daniel McArdle5aea4642020-08-05 16:59:5417// This max defines how many times we are willing to call
18// |BackoffEntry::InformOfRequest| in |DeserializeFromValue|.
19//
20// This value is meant to large enough that the computed backoff duration can
21// still be saturated. Given that the duration is an int64 and assuming 1.01 as
22// a conservative lower bound for BackoffEntry::Policy::multiply_factor,
23// ceil(log(2**63-1, 1.01)) = 4389.
24const int kMaxFailureCount = 4389;
Dan McArdle22c2f642021-03-18 23:40:1025
Dan McArdle1b605dc2021-09-23 17:54:3126// This function returns true iff |duration| is finite and can be serialized and
27// deserialized without becoming infinite. This function is aligned with the
28// latest version.
Dan McArdle22c2f642021-03-18 23:40:1029bool BackoffDurationSafeToSerialize(const base::TimeDelta& duration) {
30 return !duration.is_inf() &&
Peter Kastinge5a38ed2021-10-02 03:06:3531 !base::Microseconds(duration.InMicroseconds()).is_inf();
Dan McArdle22c2f642021-03-18 23:40:1032}
johnme6727a62a2015-05-07 13:48:3033} // namespace
34
35namespace net {
36
Maks Orlovich691496c2021-05-18 15:03:2137base::Value BackoffEntrySerializer::SerializeToValue(const BackoffEntry& entry,
38 base::Time time_now) {
Matt Menke7c5e0772022-05-31 21:35:4539 base::Value::List serialized;
40 serialized.Append(SerializationFormatVersion::kVersion2);
johnme6727a62a2015-05-07 13:48:3041
Matt Menke7c5e0772022-05-31 21:35:4542 serialized.Append(entry.failure_count());
johnme6727a62a2015-05-07 13:48:3043
Dan McArdlee4960f72021-02-04 18:01:1144 // Convert both |base::TimeTicks| values into |base::TimeDelta| values by
45 // subtracting |kZeroTicks. This way, the top-level subtraction uses
46 // |base::TimeDelta::operator-|, which has clamping semantics.
47 const base::TimeTicks kZeroTicks;
Dan McArdle3e929bc2021-02-12 16:57:5948 const base::TimeDelta kReleaseTime = entry.GetReleaseTime() - kZeroTicks;
49 const base::TimeDelta kTimeTicksNow = entry.GetTimeTicksNow() - kZeroTicks;
50 base::TimeDelta backoff_duration;
51 if (!kReleaseTime.is_inf() && !kTimeTicksNow.is_inf()) {
52 backoff_duration = kReleaseTime - kTimeTicksNow;
53 }
Dan McArdle22c2f642021-03-18 23:40:1054 if (!BackoffDurationSafeToSerialize(backoff_duration)) {
Dan McArdlee4960f72021-02-04 18:01:1155 backoff_duration = base::TimeDelta();
56 }
57
Dan McArdle22c2f642021-03-18 23:40:1058 base::Time absolute_release_time = backoff_duration + time_now;
59 // If the computed release time is infinite, default to zero. The deserializer
60 // should pick up on this.
61 if (absolute_release_time.is_inf()) {
62 absolute_release_time = base::Time();
63 }
64
johnme6727a62a2015-05-07 13:48:3065 // Redundantly stores both the remaining time delta and the absolute time.
66 // The delta is used to work around some cases where wall clock time changes.
Matt Menke7c5e0772022-05-31 21:35:4567 serialized.Append(base::NumberToString(backoff_duration.InMicroseconds()));
68 serialized.Append(
Raul Tambre8c1981d2019-02-08 02:22:2669 base::NumberToString(absolute_release_time.ToInternalValue()));
johnme6727a62a2015-05-07 13:48:3070
Maks Orlovich691496c2021-05-18 15:03:2171 return base::Value(std::move(serialized));
johnme6727a62a2015-05-07 13:48:3072}
73
Roland Bock652d22d2022-08-11 15:22:0274std::unique_ptr<BackoffEntry> BackoffEntrySerializer::DeserializeFromList(
75 const base::Value::List& serialized,
danakj7f767e62016-04-16 23:20:2376 const BackoffEntry::Policy* policy,
Greg Thompsonaa48ce8d2018-04-03 06:11:4377 const base::TickClock* tick_clock,
danakj7f767e62016-04-16 23:20:2378 base::Time time_now) {
Roland Bock652d22d2022-08-11 15:22:0279 if (serialized.size() != 4)
Maks Orlovich691496c2021-05-18 15:03:2180 return nullptr;
81
Roland Bock652d22d2022-08-11 15:22:0282 if (!serialized[0].is_int())
Maks Orlovich691496c2021-05-18 15:03:2183 return nullptr;
Roland Bock652d22d2022-08-11 15:22:0284 int version_number = serialized[0].GetInt();
Dan McArdle1b605dc2021-09-23 17:54:3185 if (version_number != kVersion1 && version_number != kVersion2)
Maks Orlovich691496c2021-05-18 15:03:2186 return nullptr;
87
Roland Bock652d22d2022-08-11 15:22:0288 if (!serialized[1].is_int())
Maks Orlovich691496c2021-05-18 15:03:2189 return nullptr;
Roland Bock652d22d2022-08-11 15:22:0290 int failure_count = serialized[1].GetInt();
Maks Orlovich691496c2021-05-18 15:03:2191 if (failure_count < 0) {
johnme6727a62a2015-05-07 13:48:3092 return nullptr;
Daniel McArdle5aea4642020-08-05 16:59:5493 }
94 failure_count = std::min(failure_count, kMaxFailureCount);
95
Dan McArdle1b605dc2021-09-23 17:54:3196 base::TimeDelta original_backoff_duration;
97 switch (version_number) {
98 case kVersion1: {
Roland Bock652d22d2022-08-11 15:22:0299 if (!serialized[2].is_double())
Dan McArdle1b605dc2021-09-23 17:54:31100 return nullptr;
Roland Bock652d22d2022-08-11 15:22:02101 double original_backoff_duration_double = serialized[2].GetDouble();
Dan McArdle1b605dc2021-09-23 17:54:31102 original_backoff_duration =
Peter Kastinge5a38ed2021-10-02 03:06:35103 base::Seconds(original_backoff_duration_double);
Dan McArdle1b605dc2021-09-23 17:54:31104 break;
105 }
106 case kVersion2: {
Roland Bock652d22d2022-08-11 15:22:02107 if (!serialized[2].is_string())
Dan McArdle1b605dc2021-09-23 17:54:31108 return nullptr;
Roland Bock652d22d2022-08-11 15:22:02109 std::string original_backoff_duration_string = serialized[2].GetString();
Dan McArdle1b605dc2021-09-23 17:54:31110 int64_t original_backoff_duration_us;
111 if (!base::StringToInt64(original_backoff_duration_string,
112 &original_backoff_duration_us)) {
113 return nullptr;
114 }
115 original_backoff_duration =
Peter Kastinge5a38ed2021-10-02 03:06:35116 base::Microseconds(original_backoff_duration_us);
Dan McArdle1b605dc2021-09-23 17:54:31117 break;
118 }
119 default:
120 NOTREACHED() << "Unexpected version_number: " << version_number;
121 }
Maks Orlovich691496c2021-05-18 15:03:21122
Roland Bock652d22d2022-08-11 15:22:02123 if (!serialized[3].is_string())
johnme6727a62a2015-05-07 13:48:30124 return nullptr;
Roland Bock652d22d2022-08-11 15:22:02125 std::string absolute_release_time_string = serialized[3].GetString();
Maks Orlovich691496c2021-05-18 15:03:21126
wtc69f8ea82015-06-04 00:08:13127 int64_t absolute_release_time_us;
johnme6727a62a2015-05-07 13:48:30128 if (!base::StringToInt64(absolute_release_time_string,
Daniel McArdle209ee462020-09-18 19:59:28129 &absolute_release_time_us)) {
johnme6727a62a2015-05-07 13:48:30130 return nullptr;
131 }
132
Tsuyoshi Horof8861cb2022-07-05 23:50:20133 auto entry = std::make_unique<BackoffEntry>(policy, tick_clock);
johnme6727a62a2015-05-07 13:48:30134
135 for (int n = 0; n < failure_count; n++)
136 entry->InformOfRequest(false);
137
johnme6727a62a2015-05-07 13:48:30138 base::Time absolute_release_time =
139 base::Time::FromInternalValue(absolute_release_time_us);
Dan McArdle22c2f642021-03-18 23:40:10140
141 base::TimeDelta backoff_duration;
142 if (absolute_release_time == base::Time()) {
143 // When the serializer cannot compute a finite release time, it uses zero.
144 // When we see this, fall back to the redundant original_backoff_duration.
johnme6727a62a2015-05-07 13:48:30145 backoff_duration = original_backoff_duration;
Dan McArdle22c2f642021-03-18 23:40:10146 } else {
147 // Before computing |backoff_duration|, throw out +/- infinity values for
148 // either operand. This way, we can use base::TimeDelta's saturated math.
149 if (absolute_release_time.is_inf() || time_now.is_inf())
150 return nullptr;
151
152 backoff_duration = absolute_release_time.ToDeltaSinceWindowsEpoch() -
153 time_now.ToDeltaSinceWindowsEpoch();
154
155 // In cases where the system wall clock is rewound, use the redundant
156 // original_backoff_duration to ensure the backoff duration isn't longer
157 // than it was before serializing (note that it's not possible to protect
158 // against the clock being wound forward).
159 if (backoff_duration > original_backoff_duration)
160 backoff_duration = original_backoff_duration;
161 }
162 if (!BackoffDurationSafeToSerialize(backoff_duration))
Daniel McArdle52ec0692020-07-06 21:50:19163 return nullptr;
Dan McArdle6d0831d2022-02-08 15:02:40164
165 const base::TimeTicks release_time =
166 entry->BackoffDurationToReleaseTime(backoff_duration);
167 if (release_time.is_inf())
168 return nullptr;
169 entry->SetCustomReleaseTime(release_time);
johnme6727a62a2015-05-07 13:48:30170
171 return entry;
172}
173
Roland Bock652d22d2022-08-11 15:22:02174std::unique_ptr<BackoffEntry> BackoffEntrySerializer::DeserializeFromValue(
175 const base::Value& serialized,
176 const BackoffEntry::Policy* policy,
177 const base::TickClock* tick_clock,
178 base::Time time_now) {
179 if (!serialized.is_list())
180 return nullptr;
181 return DeserializeFromList(serialized.GetList(), policy, tick_clock,
182 time_now);
183}
184
johnme6727a62a2015-05-07 13:48:30185} // namespace net