blob: 051696867807255c277a14a2bb586d39e971f2bb [file] [log] [blame]
Avi Drissman64595482022-09-14 20:52:291// Copyright 2015 The Chromium Authors
johnme6727a62a2015-05-07 13:48:302// 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>
Jean-Philippe Gravele69e3d22022-11-27 20:48:108#include <ostream>
dchengc7eeda422015-12-26 03:56:489#include <utility>
10
Dan McArdle1b605dc2021-09-23 17:54:3111#include "base/notreached.h"
johnme6727a62a2015-05-07 13:48:3012#include "base/strings/string_number_conversions.h"
13#include "base/time/tick_clock.h"
14#include "base/values.h"
15#include "net/base/backoff_entry.h"
16
17namespace {
Daniel McArdle5aea4642020-08-05 16:59:5418// This max defines how many times we are willing to call
Jiacheng Guo9dfe9f62022-09-21 11:35:4719// |BackoffEntry::InformOfRequest| in |DeserializeFromList|.
Daniel McArdle5aea4642020-08-05 16:59:5420//
21// This value is meant to large enough that the computed backoff duration can
22// still be saturated. Given that the duration is an int64 and assuming 1.01 as
23// a conservative lower bound for BackoffEntry::Policy::multiply_factor,
24// ceil(log(2**63-1, 1.01)) = 4389.
25const int kMaxFailureCount = 4389;
Dan McArdle22c2f642021-03-18 23:40:1026
Dan McArdle1b605dc2021-09-23 17:54:3127// This function returns true iff |duration| is finite and can be serialized and
28// deserialized without becoming infinite. This function is aligned with the
29// latest version.
Dan McArdle22c2f642021-03-18 23:40:1030bool BackoffDurationSafeToSerialize(const base::TimeDelta& duration) {
31 return !duration.is_inf() &&
Peter Kastinge5a38ed2021-10-02 03:06:3532 !base::Microseconds(duration.InMicroseconds()).is_inf();
Dan McArdle22c2f642021-03-18 23:40:1033}
johnme6727a62a2015-05-07 13:48:3034} // namespace
35
36namespace net {
37
Jiacheng Guo9dfe9f62022-09-21 11:35:4738base::Value::List BackoffEntrySerializer::SerializeToList(
39 const BackoffEntry& entry,
40 base::Time time_now) {
Matt Menke7c5e0772022-05-31 21:35:4541 base::Value::List serialized;
42 serialized.Append(SerializationFormatVersion::kVersion2);
johnme6727a62a2015-05-07 13:48:3043
Matt Menke7c5e0772022-05-31 21:35:4544 serialized.Append(entry.failure_count());
johnme6727a62a2015-05-07 13:48:3045
Dan McArdlee4960f72021-02-04 18:01:1146 // Convert both |base::TimeTicks| values into |base::TimeDelta| values by
47 // subtracting |kZeroTicks. This way, the top-level subtraction uses
48 // |base::TimeDelta::operator-|, which has clamping semantics.
49 const base::TimeTicks kZeroTicks;
Dan McArdle3e929bc2021-02-12 16:57:5950 const base::TimeDelta kReleaseTime = entry.GetReleaseTime() - kZeroTicks;
51 const base::TimeDelta kTimeTicksNow = entry.GetTimeTicksNow() - kZeroTicks;
52 base::TimeDelta backoff_duration;
53 if (!kReleaseTime.is_inf() && !kTimeTicksNow.is_inf()) {
54 backoff_duration = kReleaseTime - kTimeTicksNow;
55 }
Dan McArdle22c2f642021-03-18 23:40:1056 if (!BackoffDurationSafeToSerialize(backoff_duration)) {
Dan McArdlee4960f72021-02-04 18:01:1157 backoff_duration = base::TimeDelta();
58 }
59
Dan McArdle22c2f642021-03-18 23:40:1060 base::Time absolute_release_time = backoff_duration + time_now;
61 // If the computed release time is infinite, default to zero. The deserializer
62 // should pick up on this.
63 if (absolute_release_time.is_inf()) {
64 absolute_release_time = base::Time();
65 }
66
johnme6727a62a2015-05-07 13:48:3067 // Redundantly stores both the remaining time delta and the absolute time.
68 // The delta is used to work around some cases where wall clock time changes.
Matt Menke7c5e0772022-05-31 21:35:4569 serialized.Append(base::NumberToString(backoff_duration.InMicroseconds()));
70 serialized.Append(
Raul Tambre8c1981dd2019-02-08 02:22:2671 base::NumberToString(absolute_release_time.ToInternalValue()));
johnme6727a62a2015-05-07 13:48:3072
Jiacheng Guo9dfe9f62022-09-21 11:35:4773 return serialized;
johnme6727a62a2015-05-07 13:48:3074}
75
Roland Bock652d22d2022-08-11 15:22:0276std::unique_ptr<BackoffEntry> BackoffEntrySerializer::DeserializeFromList(
77 const base::Value::List& serialized,
danakj7f767e62016-04-16 23:20:2378 const BackoffEntry::Policy* policy,
Greg Thompsonaa48ce8d2018-04-03 06:11:4379 const base::TickClock* tick_clock,
danakj7f767e62016-04-16 23:20:2380 base::Time time_now) {
Roland Bock652d22d2022-08-11 15:22:0281 if (serialized.size() != 4)
Maks Orlovich691496c2021-05-18 15:03:2182 return nullptr;
83
Roland Bock652d22d2022-08-11 15:22:0284 if (!serialized[0].is_int())
Maks Orlovich691496c2021-05-18 15:03:2185 return nullptr;
Roland Bock652d22d2022-08-11 15:22:0286 int version_number = serialized[0].GetInt();
Dan McArdle1b605dc2021-09-23 17:54:3187 if (version_number != kVersion1 && version_number != kVersion2)
Maks Orlovich691496c2021-05-18 15:03:2188 return nullptr;
89
Roland Bock652d22d2022-08-11 15:22:0290 if (!serialized[1].is_int())
Maks Orlovich691496c2021-05-18 15:03:2191 return nullptr;
Roland Bock652d22d2022-08-11 15:22:0292 int failure_count = serialized[1].GetInt();
Maks Orlovich691496c2021-05-18 15:03:2193 if (failure_count < 0) {
johnme6727a62a2015-05-07 13:48:3094 return nullptr;
Daniel McArdle5aea4642020-08-05 16:59:5495 }
96 failure_count = std::min(failure_count, kMaxFailureCount);
97
Dan McArdle1b605dc2021-09-23 17:54:3198 base::TimeDelta original_backoff_duration;
99 switch (version_number) {
100 case kVersion1: {
Roland Bock652d22d2022-08-11 15:22:02101 if (!serialized[2].is_double())
Dan McArdle1b605dc2021-09-23 17:54:31102 return nullptr;
Roland Bock652d22d2022-08-11 15:22:02103 double original_backoff_duration_double = serialized[2].GetDouble();
Dan McArdle1b605dc2021-09-23 17:54:31104 original_backoff_duration =
Peter Kastinge5a38ed2021-10-02 03:06:35105 base::Seconds(original_backoff_duration_double);
Dan McArdle1b605dc2021-09-23 17:54:31106 break;
107 }
108 case kVersion2: {
Roland Bock652d22d2022-08-11 15:22:02109 if (!serialized[2].is_string())
Dan McArdle1b605dc2021-09-23 17:54:31110 return nullptr;
Roland Bock652d22d2022-08-11 15:22:02111 std::string original_backoff_duration_string = serialized[2].GetString();
Dan McArdle1b605dc2021-09-23 17:54:31112 int64_t original_backoff_duration_us;
113 if (!base::StringToInt64(original_backoff_duration_string,
114 &original_backoff_duration_us)) {
115 return nullptr;
116 }
117 original_backoff_duration =
Peter Kastinge5a38ed2021-10-02 03:06:35118 base::Microseconds(original_backoff_duration_us);
Dan McArdle1b605dc2021-09-23 17:54:31119 break;
120 }
121 default:
Peter Boström54bd8e32024-10-31 01:36:37122 NOTREACHED() << "Unexpected version_number: " << version_number;
Dan McArdle1b605dc2021-09-23 17:54:31123 }
Maks Orlovich691496c2021-05-18 15:03:21124
Roland Bock652d22d2022-08-11 15:22:02125 if (!serialized[3].is_string())
johnme6727a62a2015-05-07 13:48:30126 return nullptr;
Maks Orlovich691496c2021-05-18 15:03:21127
wtc69f8ea82015-06-04 00:08:13128 int64_t absolute_release_time_us;
Tom Sepez1987add2024-11-04 20:36:16129 if (!base::StringToInt64(serialized[3].GetString(),
Daniel McArdle209ee462020-09-18 19:59:28130 &absolute_release_time_us)) {
johnme6727a62a2015-05-07 13:48:30131 return nullptr;
132 }
133
Tsuyoshi Horof8861cb2022-07-05 23:50:20134 auto entry = std::make_unique<BackoffEntry>(policy, tick_clock);
johnme6727a62a2015-05-07 13:48:30135
136 for (int n = 0; n < failure_count; n++)
137 entry->InformOfRequest(false);
138
johnme6727a62a2015-05-07 13:48:30139 base::Time absolute_release_time =
140 base::Time::FromInternalValue(absolute_release_time_us);
Dan McArdle22c2f642021-03-18 23:40:10141
142 base::TimeDelta backoff_duration;
143 if (absolute_release_time == base::Time()) {
144 // When the serializer cannot compute a finite release time, it uses zero.
145 // When we see this, fall back to the redundant original_backoff_duration.
johnme6727a62a2015-05-07 13:48:30146 backoff_duration = original_backoff_duration;
Dan McArdle22c2f642021-03-18 23:40:10147 } else {
148 // Before computing |backoff_duration|, throw out +/- infinity values for
149 // either operand. This way, we can use base::TimeDelta's saturated math.
150 if (absolute_release_time.is_inf() || time_now.is_inf())
151 return nullptr;
152
153 backoff_duration = absolute_release_time.ToDeltaSinceWindowsEpoch() -
154 time_now.ToDeltaSinceWindowsEpoch();
155
156 // In cases where the system wall clock is rewound, use the redundant
157 // original_backoff_duration to ensure the backoff duration isn't longer
158 // than it was before serializing (note that it's not possible to protect
159 // against the clock being wound forward).
160 if (backoff_duration > original_backoff_duration)
161 backoff_duration = original_backoff_duration;
162 }
163 if (!BackoffDurationSafeToSerialize(backoff_duration))
Daniel McArdle52ec0692020-07-06 21:50:19164 return nullptr;
Dan McArdle6d0831d2022-02-08 15:02:40165
166 const base::TimeTicks release_time =
167 entry->BackoffDurationToReleaseTime(backoff_duration);
168 if (release_time.is_inf())
169 return nullptr;
170 entry->SetCustomReleaseTime(release_time);
johnme6727a62a2015-05-07 13:48:30171
172 return entry;
173}
174
johnme6727a62a2015-05-07 13:48:30175} // namespace net