1*6777b538SAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/base/backoff_entry_serializer.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <algorithm>
8*6777b538SAndroid Build Coastguard Worker #include <ostream>
9*6777b538SAndroid Build Coastguard Worker #include <utility>
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/time/tick_clock.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
15*6777b538SAndroid Build Coastguard Worker #include "net/base/backoff_entry.h"
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Worker namespace {
18*6777b538SAndroid Build Coastguard Worker // This max defines how many times we are willing to call
19*6777b538SAndroid Build Coastguard Worker // |BackoffEntry::InformOfRequest| in |DeserializeFromList|.
20*6777b538SAndroid Build Coastguard Worker //
21*6777b538SAndroid Build Coastguard Worker // This value is meant to large enough that the computed backoff duration can
22*6777b538SAndroid Build Coastguard Worker // still be saturated. Given that the duration is an int64 and assuming 1.01 as
23*6777b538SAndroid Build Coastguard Worker // a conservative lower bound for BackoffEntry::Policy::multiply_factor,
24*6777b538SAndroid Build Coastguard Worker // ceil(log(2**63-1, 1.01)) = 4389.
25*6777b538SAndroid Build Coastguard Worker const int kMaxFailureCount = 4389;
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker // This function returns true iff |duration| is finite and can be serialized and
28*6777b538SAndroid Build Coastguard Worker // deserialized without becoming infinite. This function is aligned with the
29*6777b538SAndroid Build Coastguard Worker // latest version.
BackoffDurationSafeToSerialize(const base::TimeDelta & duration)30*6777b538SAndroid Build Coastguard Worker bool BackoffDurationSafeToSerialize(const base::TimeDelta& duration) {
31*6777b538SAndroid Build Coastguard Worker return !duration.is_inf() &&
32*6777b538SAndroid Build Coastguard Worker !base::Microseconds(duration.InMicroseconds()).is_inf();
33*6777b538SAndroid Build Coastguard Worker }
34*6777b538SAndroid Build Coastguard Worker } // namespace
35*6777b538SAndroid Build Coastguard Worker
36*6777b538SAndroid Build Coastguard Worker namespace net {
37*6777b538SAndroid Build Coastguard Worker
SerializeToList(const BackoffEntry & entry,base::Time time_now)38*6777b538SAndroid Build Coastguard Worker base::Value::List BackoffEntrySerializer::SerializeToList(
39*6777b538SAndroid Build Coastguard Worker const BackoffEntry& entry,
40*6777b538SAndroid Build Coastguard Worker base::Time time_now) {
41*6777b538SAndroid Build Coastguard Worker base::Value::List serialized;
42*6777b538SAndroid Build Coastguard Worker serialized.Append(SerializationFormatVersion::kVersion2);
43*6777b538SAndroid Build Coastguard Worker
44*6777b538SAndroid Build Coastguard Worker serialized.Append(entry.failure_count());
45*6777b538SAndroid Build Coastguard Worker
46*6777b538SAndroid Build Coastguard Worker // Convert both |base::TimeTicks| values into |base::TimeDelta| values by
47*6777b538SAndroid Build Coastguard Worker // subtracting |kZeroTicks. This way, the top-level subtraction uses
48*6777b538SAndroid Build Coastguard Worker // |base::TimeDelta::operator-|, which has clamping semantics.
49*6777b538SAndroid Build Coastguard Worker const base::TimeTicks kZeroTicks;
50*6777b538SAndroid Build Coastguard Worker const base::TimeDelta kReleaseTime = entry.GetReleaseTime() - kZeroTicks;
51*6777b538SAndroid Build Coastguard Worker const base::TimeDelta kTimeTicksNow = entry.GetTimeTicksNow() - kZeroTicks;
52*6777b538SAndroid Build Coastguard Worker base::TimeDelta backoff_duration;
53*6777b538SAndroid Build Coastguard Worker if (!kReleaseTime.is_inf() && !kTimeTicksNow.is_inf()) {
54*6777b538SAndroid Build Coastguard Worker backoff_duration = kReleaseTime - kTimeTicksNow;
55*6777b538SAndroid Build Coastguard Worker }
56*6777b538SAndroid Build Coastguard Worker if (!BackoffDurationSafeToSerialize(backoff_duration)) {
57*6777b538SAndroid Build Coastguard Worker backoff_duration = base::TimeDelta();
58*6777b538SAndroid Build Coastguard Worker }
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard Worker base::Time absolute_release_time = backoff_duration + time_now;
61*6777b538SAndroid Build Coastguard Worker // If the computed release time is infinite, default to zero. The deserializer
62*6777b538SAndroid Build Coastguard Worker // should pick up on this.
63*6777b538SAndroid Build Coastguard Worker if (absolute_release_time.is_inf()) {
64*6777b538SAndroid Build Coastguard Worker absolute_release_time = base::Time();
65*6777b538SAndroid Build Coastguard Worker }
66*6777b538SAndroid Build Coastguard Worker
67*6777b538SAndroid Build Coastguard Worker // Redundantly stores both the remaining time delta and the absolute time.
68*6777b538SAndroid Build Coastguard Worker // The delta is used to work around some cases where wall clock time changes.
69*6777b538SAndroid Build Coastguard Worker serialized.Append(base::NumberToString(backoff_duration.InMicroseconds()));
70*6777b538SAndroid Build Coastguard Worker serialized.Append(
71*6777b538SAndroid Build Coastguard Worker base::NumberToString(absolute_release_time.ToInternalValue()));
72*6777b538SAndroid Build Coastguard Worker
73*6777b538SAndroid Build Coastguard Worker return serialized;
74*6777b538SAndroid Build Coastguard Worker }
75*6777b538SAndroid Build Coastguard Worker
DeserializeFromList(const base::Value::List & serialized,const BackoffEntry::Policy * policy,const base::TickClock * tick_clock,base::Time time_now)76*6777b538SAndroid Build Coastguard Worker std::unique_ptr<BackoffEntry> BackoffEntrySerializer::DeserializeFromList(
77*6777b538SAndroid Build Coastguard Worker const base::Value::List& serialized,
78*6777b538SAndroid Build Coastguard Worker const BackoffEntry::Policy* policy,
79*6777b538SAndroid Build Coastguard Worker const base::TickClock* tick_clock,
80*6777b538SAndroid Build Coastguard Worker base::Time time_now) {
81*6777b538SAndroid Build Coastguard Worker if (serialized.size() != 4)
82*6777b538SAndroid Build Coastguard Worker return nullptr;
83*6777b538SAndroid Build Coastguard Worker
84*6777b538SAndroid Build Coastguard Worker if (!serialized[0].is_int())
85*6777b538SAndroid Build Coastguard Worker return nullptr;
86*6777b538SAndroid Build Coastguard Worker int version_number = serialized[0].GetInt();
87*6777b538SAndroid Build Coastguard Worker if (version_number != kVersion1 && version_number != kVersion2)
88*6777b538SAndroid Build Coastguard Worker return nullptr;
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker if (!serialized[1].is_int())
91*6777b538SAndroid Build Coastguard Worker return nullptr;
92*6777b538SAndroid Build Coastguard Worker int failure_count = serialized[1].GetInt();
93*6777b538SAndroid Build Coastguard Worker if (failure_count < 0) {
94*6777b538SAndroid Build Coastguard Worker return nullptr;
95*6777b538SAndroid Build Coastguard Worker }
96*6777b538SAndroid Build Coastguard Worker failure_count = std::min(failure_count, kMaxFailureCount);
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker base::TimeDelta original_backoff_duration;
99*6777b538SAndroid Build Coastguard Worker switch (version_number) {
100*6777b538SAndroid Build Coastguard Worker case kVersion1: {
101*6777b538SAndroid Build Coastguard Worker if (!serialized[2].is_double())
102*6777b538SAndroid Build Coastguard Worker return nullptr;
103*6777b538SAndroid Build Coastguard Worker double original_backoff_duration_double = serialized[2].GetDouble();
104*6777b538SAndroid Build Coastguard Worker original_backoff_duration =
105*6777b538SAndroid Build Coastguard Worker base::Seconds(original_backoff_duration_double);
106*6777b538SAndroid Build Coastguard Worker break;
107*6777b538SAndroid Build Coastguard Worker }
108*6777b538SAndroid Build Coastguard Worker case kVersion2: {
109*6777b538SAndroid Build Coastguard Worker if (!serialized[2].is_string())
110*6777b538SAndroid Build Coastguard Worker return nullptr;
111*6777b538SAndroid Build Coastguard Worker std::string original_backoff_duration_string = serialized[2].GetString();
112*6777b538SAndroid Build Coastguard Worker int64_t original_backoff_duration_us;
113*6777b538SAndroid Build Coastguard Worker if (!base::StringToInt64(original_backoff_duration_string,
114*6777b538SAndroid Build Coastguard Worker &original_backoff_duration_us)) {
115*6777b538SAndroid Build Coastguard Worker return nullptr;
116*6777b538SAndroid Build Coastguard Worker }
117*6777b538SAndroid Build Coastguard Worker original_backoff_duration =
118*6777b538SAndroid Build Coastguard Worker base::Microseconds(original_backoff_duration_us);
119*6777b538SAndroid Build Coastguard Worker break;
120*6777b538SAndroid Build Coastguard Worker }
121*6777b538SAndroid Build Coastguard Worker default:
122*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Unexpected version_number: " << version_number;
123*6777b538SAndroid Build Coastguard Worker }
124*6777b538SAndroid Build Coastguard Worker
125*6777b538SAndroid Build Coastguard Worker if (!serialized[3].is_string())
126*6777b538SAndroid Build Coastguard Worker return nullptr;
127*6777b538SAndroid Build Coastguard Worker std::string absolute_release_time_string = serialized[3].GetString();
128*6777b538SAndroid Build Coastguard Worker
129*6777b538SAndroid Build Coastguard Worker int64_t absolute_release_time_us;
130*6777b538SAndroid Build Coastguard Worker if (!base::StringToInt64(absolute_release_time_string,
131*6777b538SAndroid Build Coastguard Worker &absolute_release_time_us)) {
132*6777b538SAndroid Build Coastguard Worker return nullptr;
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Worker auto entry = std::make_unique<BackoffEntry>(policy, tick_clock);
136*6777b538SAndroid Build Coastguard Worker
137*6777b538SAndroid Build Coastguard Worker for (int n = 0; n < failure_count; n++)
138*6777b538SAndroid Build Coastguard Worker entry->InformOfRequest(false);
139*6777b538SAndroid Build Coastguard Worker
140*6777b538SAndroid Build Coastguard Worker base::Time absolute_release_time =
141*6777b538SAndroid Build Coastguard Worker base::Time::FromInternalValue(absolute_release_time_us);
142*6777b538SAndroid Build Coastguard Worker
143*6777b538SAndroid Build Coastguard Worker base::TimeDelta backoff_duration;
144*6777b538SAndroid Build Coastguard Worker if (absolute_release_time == base::Time()) {
145*6777b538SAndroid Build Coastguard Worker // When the serializer cannot compute a finite release time, it uses zero.
146*6777b538SAndroid Build Coastguard Worker // When we see this, fall back to the redundant original_backoff_duration.
147*6777b538SAndroid Build Coastguard Worker backoff_duration = original_backoff_duration;
148*6777b538SAndroid Build Coastguard Worker } else {
149*6777b538SAndroid Build Coastguard Worker // Before computing |backoff_duration|, throw out +/- infinity values for
150*6777b538SAndroid Build Coastguard Worker // either operand. This way, we can use base::TimeDelta's saturated math.
151*6777b538SAndroid Build Coastguard Worker if (absolute_release_time.is_inf() || time_now.is_inf())
152*6777b538SAndroid Build Coastguard Worker return nullptr;
153*6777b538SAndroid Build Coastguard Worker
154*6777b538SAndroid Build Coastguard Worker backoff_duration = absolute_release_time.ToDeltaSinceWindowsEpoch() -
155*6777b538SAndroid Build Coastguard Worker time_now.ToDeltaSinceWindowsEpoch();
156*6777b538SAndroid Build Coastguard Worker
157*6777b538SAndroid Build Coastguard Worker // In cases where the system wall clock is rewound, use the redundant
158*6777b538SAndroid Build Coastguard Worker // original_backoff_duration to ensure the backoff duration isn't longer
159*6777b538SAndroid Build Coastguard Worker // than it was before serializing (note that it's not possible to protect
160*6777b538SAndroid Build Coastguard Worker // against the clock being wound forward).
161*6777b538SAndroid Build Coastguard Worker if (backoff_duration > original_backoff_duration)
162*6777b538SAndroid Build Coastguard Worker backoff_duration = original_backoff_duration;
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker if (!BackoffDurationSafeToSerialize(backoff_duration))
165*6777b538SAndroid Build Coastguard Worker return nullptr;
166*6777b538SAndroid Build Coastguard Worker
167*6777b538SAndroid Build Coastguard Worker const base::TimeTicks release_time =
168*6777b538SAndroid Build Coastguard Worker entry->BackoffDurationToReleaseTime(backoff_duration);
169*6777b538SAndroid Build Coastguard Worker if (release_time.is_inf())
170*6777b538SAndroid Build Coastguard Worker return nullptr;
171*6777b538SAndroid Build Coastguard Worker entry->SetCustomReleaseTime(release_time);
172*6777b538SAndroid Build Coastguard Worker
173*6777b538SAndroid Build Coastguard Worker return entry;
174*6777b538SAndroid Build Coastguard Worker }
175*6777b538SAndroid Build Coastguard Worker
176*6777b538SAndroid Build Coastguard Worker } // namespace net
177