AWS SDK for C++

AWS SDK for C++ Version 1.11.887

Loading...
Searching...
No Matches
ClockSkew.h
1
6#pragma once
7
8#include <aws/core/Core_EXPORTS.h>
9#include <aws/core/http/HttpRequest.h>
10#include <aws/core/utils/Chrono.h>
11#include <aws/core/utils/DateTime.h>
12#include <aws/core/utils/StringUtils.h>
13#include <aws/core/client/AWSError.h>
14#include <aws/core/client/CoreErrors.h>
15#include <aws/crt/Optional.h>
16#include <atomic>
17#include <chrono>
18
19namespace Aws
20{
21 namespace Internal
22 {
23 // AttemptSkew is owned by the client, not here.
24
25 static const std::chrono::milliseconds CLOCK_SKEW_DETECTION_THRESHOLD = std::chrono::minutes(4);
26 static const std::chrono::milliseconds CLOCK_SKEW_MAX_TRUSTED_REQUEST_DURATION = std::chrono::minutes(15);
27 static const char CLOCK_SKEW_AGE_HEADER[] = "age";
28
30 {
31 Aws::Crt::Optional<Aws::Utils::DateTime> serverTime; // empty when the response carries no usable Date header
35
36 ClockSkewMeasurement(const Aws::Crt::Optional<Aws::Utils::DateTime>& serverTime,
39 bool servedFromCache)
44 };
45
47 const Aws::Utils::DateTime& timeRequestSent,
48 const Aws::Utils::DateTime& timeResponseReceived)
49 {
50 const auto dateIt = headers.find(Aws::Utils::StringUtils::ToLower(Aws::Http::DATE_HEADER));
51 Aws::Crt::Optional<Aws::Utils::DateTime> serverTime;
52 if (dateIt != headers.end())
53 {
54 const Aws::Utils::DateTime parsed(dateIt->second.c_str(), Aws::Utils::DateFormat::AutoDetect);
55 if (parsed.WasParseSuccessful())
56 {
57 serverTime = parsed;
58 }
59 }
60 const bool servedFromCache = headers.find(CLOCK_SKEW_AGE_HEADER) != headers.end();
61 return ClockSkewMeasurement(serverTime, timeRequestSent, timeResponseReceived, servedFromCache);
62 }
63
64 inline Aws::Crt::Optional<std::chrono::milliseconds> ComputeClockSkewCandidate(const ClockSkewMeasurement& measurement)
65 {
66 if (!measurement.serverTime.has_value() || measurement.servedFromCache)
67 {
68 return Aws::Crt::Optional<std::chrono::milliseconds>{};
69 }
70
71 const int64_t sentMs = measurement.timeRequestSent.Millis();
72 const int64_t receivedMs = measurement.timeResponseReceived.Millis();
73 const int64_t serverMs = measurement.serverTime.value().Millis();
74
75 const std::chrono::milliseconds elapsed{receivedMs - sentMs};
77 {
78 return Aws::Crt::Optional<std::chrono::milliseconds>{};
79 }
80
81 // Server Date is assumed to be from the round-trip midpoint (NTP offset, RFC 5905 s8).
82 const int64_t midpointMs = sentMs + (receivedMs - sentMs) / 2;
83 return Aws::Crt::Optional<std::chrono::milliseconds>(std::chrono::milliseconds{serverMs - midpointMs});
84 }
85
86 // Clock-skew error codes. Matched by CoreErrors enum where one exists; AuthFailure (EC2) has no
87 // CoreErrors enum, so it is matched by name -- the same enum+name shape as IsThrottlingResponse.
89 {
90 switch (error.GetErrorType())
91 {
96 return true;
97 default:
98 return error.GetExceptionName() == "AuthFailure";
99 }
100 }
101
103 {
104 bool skewExceedsThreshold = false; // caller ANDs this with the error-code check before retrying
105 std::chrono::milliseconds skew{0};
106 };
107
108 class AWS_CORE_LOCAL ClientSkew
109 {
110 public:
111 explicit ClientSkew(std::chrono::milliseconds initial) : m_skew(initial) {}
112
113 std::chrono::milliseconds Load() const { return m_skew.load(); }
114
115 // Runs on every response; a surviving candidate is stored, so a stale value self-heals.
116 Aws::Crt::Optional<std::chrono::milliseconds> RecordResponse(const ClockSkewMeasurement& measurement)
117 {
118 Aws::Crt::Optional<std::chrono::milliseconds> candidate = ComputeClockSkewCandidate(measurement);
119 if (candidate.has_value())
120 {
121 m_skew.store(candidate.value());
122 }
123 return candidate;
124 }
125
126 ClockSkewAdjustment EvaluateFailure(const ClockSkewMeasurement& measurement, std::chrono::milliseconds attemptSkew)
127 {
128 const Aws::Crt::Optional<std::chrono::milliseconds> candidate = RecordResponse(measurement);
129 ClockSkewAdjustment adjustment;
130 adjustment.skew = m_skew.load();
131 // Retryable when the applied skew is off from the observed skew by more than the threshold.
132 if (candidate.has_value())
133 {
134 const std::chrono::milliseconds absDelta = Aws::chrono::abs(attemptSkew - candidate.value());
136 }
137 return adjustment;
138 }
139
140 private:
141 std::atomic<std::chrono::milliseconds> m_skew;
142 };
143 } // namespace Internal
144} // namespace Aws
const Aws::String & GetExceptionName() const
Definition AWSError.h:141
const ERROR_TYPE GetErrorType() const
Definition AWSError.h:137
std::chrono::milliseconds Load() const
Definition ClockSkew.h:113
Aws::Crt::Optional< std::chrono::milliseconds > RecordResponse(const ClockSkewMeasurement &measurement)
Definition ClockSkew.h:116
ClockSkewAdjustment EvaluateFailure(const ClockSkewMeasurement &measurement, std::chrono::milliseconds attemptSkew)
Definition ClockSkew.h:126
ClientSkew(std::chrono::milliseconds initial)
Definition ClockSkew.h:111
int64_t Millis() const
bool WasParseSuccessful() const
Definition DateTime.h:130
static Aws::String ToLower(const char *source)
AWS_CORE_API const char DATE_HEADER[]
Aws::Map< Aws::String, Aws::String > HeaderValueCollection
Definition HttpTypes.h:56
ClockSkewMeasurement MakeClockSkewMeasurement(const Aws::Http::HeaderValueCollection &headers, const Aws::Utils::DateTime &timeRequestSent, const Aws::Utils::DateTime &timeResponseReceived)
Definition ClockSkew.h:46
static const char CLOCK_SKEW_AGE_HEADER[]
Definition ClockSkew.h:27
static const std::chrono::milliseconds CLOCK_SKEW_DETECTION_THRESHOLD
Definition ClockSkew.h:25
static const std::chrono::milliseconds CLOCK_SKEW_MAX_TRUSTED_REQUEST_DURATION
Definition ClockSkew.h:26
bool IsClockSkewError(const Aws::Client::AWSError< Aws::Client::CoreErrors > &error)
Definition ClockSkew.h:88
Aws::Crt::Optional< std::chrono::milliseconds > ComputeClockSkewCandidate(const ClockSkewMeasurement &measurement)
Definition ClockSkew.h:64
constexpr std::enable_if< std::numeric_limits< Rep >::is_signed, std::chrono::duration< Rep, Period > >::type abs(std::chrono::duration< Rep, Period > d)
Definition Chrono.h:33
std::chrono::milliseconds skew
Definition ClockSkew.h:105
Aws::Utils::DateTime timeResponseReceived
Definition ClockSkew.h:33
Aws::Utils::DateTime timeRequestSent
Definition ClockSkew.h:32
ClockSkewMeasurement(const Aws::Crt::Optional< Aws::Utils::DateTime > &serverTime, const Aws::Utils::DateTime &timeRequestSent, const Aws::Utils::DateTime &timeResponseReceived, bool servedFromCache)
Definition ClockSkew.h:36
Aws::Crt::Optional< Aws::Utils::DateTime > serverTime
Definition ClockSkew.h:31