Avi Drissman | 6459548 | 2022-09-14 20:52:29 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 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 McArdle | 5aea464 | 2020-08-05 16:59:54 | [diff] [blame] | 7 | #include <algorithm> |
Jean-Philippe Gravel | e69e3d2 | 2022-11-27 20:48:10 | [diff] [blame] | 8 | #include <ostream> |
dcheng | c7eeda42 | 2015-12-26 03:56:48 | [diff] [blame] | 9 | #include <utility> |
| 10 | |
Dan McArdle | 1b605dc | 2021-09-23 17:54:31 | [diff] [blame] | 11 | #include "base/notreached.h" |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 12 | #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 | |
| 17 | namespace { |
Daniel McArdle | 5aea464 | 2020-08-05 16:59:54 | [diff] [blame] | 18 | // This max defines how many times we are willing to call |
Jiacheng Guo | 9dfe9f6 | 2022-09-21 11:35:47 | [diff] [blame] | 19 | // |BackoffEntry::InformOfRequest| in |DeserializeFromList|. |
Daniel McArdle | 5aea464 | 2020-08-05 16:59:54 | [diff] [blame] | 20 | // |
| 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. |
| 25 | const int kMaxFailureCount = 4389; |
Dan McArdle | 22c2f64 | 2021-03-18 23:40:10 | [diff] [blame] | 26 | |
Dan McArdle | 1b605dc | 2021-09-23 17:54:31 | [diff] [blame] | 27 | // 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 McArdle | 22c2f64 | 2021-03-18 23:40:10 | [diff] [blame] | 30 | bool BackoffDurationSafeToSerialize(const base::TimeDelta& duration) { |
| 31 | return !duration.is_inf() && |
Peter Kasting | e5a38ed | 2021-10-02 03:06:35 | [diff] [blame] | 32 | !base::Microseconds(duration.InMicroseconds()).is_inf(); |
Dan McArdle | 22c2f64 | 2021-03-18 23:40:10 | [diff] [blame] | 33 | } |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 34 | } // namespace |
| 35 | |
| 36 | namespace net { |
| 37 | |
Jiacheng Guo | 9dfe9f6 | 2022-09-21 11:35:47 | [diff] [blame] | 38 | base::Value::List BackoffEntrySerializer::SerializeToList( |
| 39 | const BackoffEntry& entry, |
| 40 | base::Time time_now) { |
Matt Menke | 7c5e077 | 2022-05-31 21:35:45 | [diff] [blame] | 41 | base::Value::List serialized; |
| 42 | serialized.Append(SerializationFormatVersion::kVersion2); |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 43 | |
Matt Menke | 7c5e077 | 2022-05-31 21:35:45 | [diff] [blame] | 44 | serialized.Append(entry.failure_count()); |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 45 | |
Dan McArdle | e4960f7 | 2021-02-04 18:01:11 | [diff] [blame] | 46 | // 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 McArdle | 3e929bc | 2021-02-12 16:57:59 | [diff] [blame] | 50 | 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 McArdle | 22c2f64 | 2021-03-18 23:40:10 | [diff] [blame] | 56 | if (!BackoffDurationSafeToSerialize(backoff_duration)) { |
Dan McArdle | e4960f7 | 2021-02-04 18:01:11 | [diff] [blame] | 57 | backoff_duration = base::TimeDelta(); |
| 58 | } |
| 59 | |
Dan McArdle | 22c2f64 | 2021-03-18 23:40:10 | [diff] [blame] | 60 | 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 | |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 67 | // 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 Menke | 7c5e077 | 2022-05-31 21:35:45 | [diff] [blame] | 69 | serialized.Append(base::NumberToString(backoff_duration.InMicroseconds())); |
| 70 | serialized.Append( |
Raul Tambre | 8c1981dd | 2019-02-08 02:22:26 | [diff] [blame] | 71 | base::NumberToString(absolute_release_time.ToInternalValue())); |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 72 | |
Jiacheng Guo | 9dfe9f6 | 2022-09-21 11:35:47 | [diff] [blame] | 73 | return serialized; |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 74 | } |
| 75 | |
Roland Bock | 652d22d | 2022-08-11 15:22:02 | [diff] [blame] | 76 | std::unique_ptr<BackoffEntry> BackoffEntrySerializer::DeserializeFromList( |
| 77 | const base::Value::List& serialized, |
danakj | 7f767e6 | 2016-04-16 23:20:23 | [diff] [blame] | 78 | const BackoffEntry::Policy* policy, |
Greg Thompson | aa48ce8d | 2018-04-03 06:11:43 | [diff] [blame] | 79 | const base::TickClock* tick_clock, |
danakj | 7f767e6 | 2016-04-16 23:20:23 | [diff] [blame] | 80 | base::Time time_now) { |
Roland Bock | 652d22d | 2022-08-11 15:22:02 | [diff] [blame] | 81 | if (serialized.size() != 4) |
Maks Orlovich | 691496c | 2021-05-18 15:03:21 | [diff] [blame] | 82 | return nullptr; |
| 83 | |
Roland Bock | 652d22d | 2022-08-11 15:22:02 | [diff] [blame] | 84 | if (!serialized[0].is_int()) |
Maks Orlovich | 691496c | 2021-05-18 15:03:21 | [diff] [blame] | 85 | return nullptr; |
Roland Bock | 652d22d | 2022-08-11 15:22:02 | [diff] [blame] | 86 | int version_number = serialized[0].GetInt(); |
Dan McArdle | 1b605dc | 2021-09-23 17:54:31 | [diff] [blame] | 87 | if (version_number != kVersion1 && version_number != kVersion2) |
Maks Orlovich | 691496c | 2021-05-18 15:03:21 | [diff] [blame] | 88 | return nullptr; |
| 89 | |
Roland Bock | 652d22d | 2022-08-11 15:22:02 | [diff] [blame] | 90 | if (!serialized[1].is_int()) |
Maks Orlovich | 691496c | 2021-05-18 15:03:21 | [diff] [blame] | 91 | return nullptr; |
Roland Bock | 652d22d | 2022-08-11 15:22:02 | [diff] [blame] | 92 | int failure_count = serialized[1].GetInt(); |
Maks Orlovich | 691496c | 2021-05-18 15:03:21 | [diff] [blame] | 93 | if (failure_count < 0) { |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 94 | return nullptr; |
Daniel McArdle | 5aea464 | 2020-08-05 16:59:54 | [diff] [blame] | 95 | } |
| 96 | failure_count = std::min(failure_count, kMaxFailureCount); |
| 97 | |
Dan McArdle | 1b605dc | 2021-09-23 17:54:31 | [diff] [blame] | 98 | base::TimeDelta original_backoff_duration; |
| 99 | switch (version_number) { |
| 100 | case kVersion1: { |
Roland Bock | 652d22d | 2022-08-11 15:22:02 | [diff] [blame] | 101 | if (!serialized[2].is_double()) |
Dan McArdle | 1b605dc | 2021-09-23 17:54:31 | [diff] [blame] | 102 | return nullptr; |
Roland Bock | 652d22d | 2022-08-11 15:22:02 | [diff] [blame] | 103 | double original_backoff_duration_double = serialized[2].GetDouble(); |
Dan McArdle | 1b605dc | 2021-09-23 17:54:31 | [diff] [blame] | 104 | original_backoff_duration = |
Peter Kasting | e5a38ed | 2021-10-02 03:06:35 | [diff] [blame] | 105 | base::Seconds(original_backoff_duration_double); |
Dan McArdle | 1b605dc | 2021-09-23 17:54:31 | [diff] [blame] | 106 | break; |
| 107 | } |
| 108 | case kVersion2: { |
Roland Bock | 652d22d | 2022-08-11 15:22:02 | [diff] [blame] | 109 | if (!serialized[2].is_string()) |
Dan McArdle | 1b605dc | 2021-09-23 17:54:31 | [diff] [blame] | 110 | return nullptr; |
Roland Bock | 652d22d | 2022-08-11 15:22:02 | [diff] [blame] | 111 | std::string original_backoff_duration_string = serialized[2].GetString(); |
Dan McArdle | 1b605dc | 2021-09-23 17:54:31 | [diff] [blame] | 112 | 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 Kasting | e5a38ed | 2021-10-02 03:06:35 | [diff] [blame] | 118 | base::Microseconds(original_backoff_duration_us); |
Dan McArdle | 1b605dc | 2021-09-23 17:54:31 | [diff] [blame] | 119 | break; |
| 120 | } |
| 121 | default: |
Peter Boström | 54bd8e3 | 2024-10-31 01:36:37 | [diff] [blame] | 122 | NOTREACHED() << "Unexpected version_number: " << version_number; |
Dan McArdle | 1b605dc | 2021-09-23 17:54:31 | [diff] [blame] | 123 | } |
Maks Orlovich | 691496c | 2021-05-18 15:03:21 | [diff] [blame] | 124 | |
Roland Bock | 652d22d | 2022-08-11 15:22:02 | [diff] [blame] | 125 | if (!serialized[3].is_string()) |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 126 | return nullptr; |
Maks Orlovich | 691496c | 2021-05-18 15:03:21 | [diff] [blame] | 127 | |
wtc | 69f8ea8 | 2015-06-04 00:08:13 | [diff] [blame] | 128 | int64_t absolute_release_time_us; |
Tom Sepez | 1987add | 2024-11-04 20:36:16 | [diff] [blame] | 129 | if (!base::StringToInt64(serialized[3].GetString(), |
Daniel McArdle | 209ee46 | 2020-09-18 19:59:28 | [diff] [blame] | 130 | &absolute_release_time_us)) { |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 131 | return nullptr; |
| 132 | } |
| 133 | |
Tsuyoshi Horo | f8861cb | 2022-07-05 23:50:20 | [diff] [blame] | 134 | auto entry = std::make_unique<BackoffEntry>(policy, tick_clock); |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 135 | |
| 136 | for (int n = 0; n < failure_count; n++) |
| 137 | entry->InformOfRequest(false); |
| 138 | |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 139 | base::Time absolute_release_time = |
| 140 | base::Time::FromInternalValue(absolute_release_time_us); |
Dan McArdle | 22c2f64 | 2021-03-18 23:40:10 | [diff] [blame] | 141 | |
| 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. |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 146 | backoff_duration = original_backoff_duration; |
Dan McArdle | 22c2f64 | 2021-03-18 23:40:10 | [diff] [blame] | 147 | } 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 McArdle | 52ec069 | 2020-07-06 21:50:19 | [diff] [blame] | 164 | return nullptr; |
Dan McArdle | 6d0831d | 2022-02-08 15:02:40 | [diff] [blame] | 165 | |
| 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); |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 171 | |
| 172 | return entry; |
| 173 | } |
| 174 | |
johnme | 6727a62a | 2015-05-07 13:48:30 | [diff] [blame] | 175 | } // namespace net |