1
#include "source/common/router/reset_header_parser.h"
2

            
3
#include <cstdint>
4

            
5
#include "source/common/common/assert.h"
6

            
7
#include "absl/strings/numbers.h"
8

            
9
namespace Envoy {
10
namespace Router {
11

            
12
ResetHeaderParserImpl::ResetHeaderParserImpl(
13
    const envoy::config::route::v3::RetryPolicy::ResetHeader& config)
14
20
    : name_(config.name()) {
15
20
  switch (config.format()) {
16
    PANIC_ON_PROTO_ENUM_SENTINEL_VALUES;
17
13
  case envoy::config::route::v3::RetryPolicy::SECONDS:
18
13
    format_ = ResetHeaderFormat::Seconds;
19
13
    break;
20
7
  case envoy::config::route::v3::RetryPolicy::UNIX_TIMESTAMP:
21
7
    format_ = ResetHeaderFormat::UnixTimestamp;
22
7
    break;
23
20
  }
24
20
}
25

            
26
absl::optional<std::chrono::milliseconds>
27
ResetHeaderParserImpl::parseInterval(TimeSource& time_source,
28
24
                                     const Http::HeaderMap& headers) const {
29
24
  const auto header = headers.get(name_);
30

            
31
24
  if (header.empty()) {
32
5
    return absl::nullopt;
33
5
  }
34

            
35
  // This is effectively a trusted header so per the API only using the first value is used.
36
19
  const auto& header_value = header[0]->value().getStringView();
37
19
  uint64_t num_seconds{};
38

            
39
19
  switch (format_) {
40
12
  case ResetHeaderFormat::Seconds:
41
12
    if (absl::SimpleAtoi(header_value, &num_seconds)) {
42
10
      return absl::optional<std::chrono::milliseconds>(num_seconds * 1000UL);
43
10
    }
44
2
    break;
45

            
46
7
  case ResetHeaderFormat::UnixTimestamp:
47
7
    if (absl::SimpleAtoi(header_value, &num_seconds)) {
48
6
      const uint64_t timestamp = DateUtil::nowToSeconds(time_source);
49

            
50
6
      if (num_seconds < timestamp) {
51
1
        return absl::nullopt;
52
1
      }
53

            
54
5
      const uint64_t interval = num_seconds - timestamp;
55
5
      return absl::optional<std::chrono::milliseconds>(interval * 1000UL);
56
6
    }
57
1
    break;
58
19
  }
59

            
60
3
  return absl::nullopt;
61
19
}
62

            
63
} // namespace Router
64
} // namespace Envoy