backoff_entry_serializer.cc 6.6 KB

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