1
#include "source/extensions/config_subscription/rest/rest_api_fetcher.h"
2

            
3
#include <chrono>
4
#include <cstdint>
5
#include <string>
6

            
7
#include "source/common/common/enum_to_int.h"
8
#include "source/common/config/utility.h"
9
#include "source/common/http/message_impl.h"
10
#include "source/common/http/utility.h"
11

            
12
namespace Envoy {
13
namespace Http {
14

            
15
RestApiFetcher::RestApiFetcher(Upstream::ClusterManager& cm, const std::string& remote_cluster_name,
16
                               Event::Dispatcher& dispatcher, Random::RandomGenerator& random,
17
                               std::chrono::milliseconds refresh_interval,
18
                               std::chrono::milliseconds request_timeout)
19
18
    : remote_cluster_name_(remote_cluster_name), cm_(cm), random_(random),
20
18
      refresh_interval_(refresh_interval), request_timeout_(request_timeout),
21
25
      refresh_timer_(dispatcher.createTimer([this]() -> void { refresh(); })) {}
22

            
23
18
RestApiFetcher::~RestApiFetcher() {
24
18
  if (active_request_) {
25
15
    active_request_->cancel();
26
15
  }
27
18
}
28

            
29
17
void RestApiFetcher::initialize() { refresh(); }
30

            
31
void RestApiFetcher::onSuccess(const Http::AsyncClient::Request& request,
32
19
                               Http::ResponseMessagePtr&& response) {
33
19
  uint64_t response_code = Http::Utility::getResponseStatus(response->headers());
34
19
  if (response_code == enumToInt(Http::Code::NotModified)) {
35
1
    requestComplete();
36
1
    return;
37
18
  } else if (response_code != enumToInt(Http::Code::OK)) {
38
    onFailure(request, Http::AsyncClient::FailureReason::Reset);
39
    return;
40
  }
41

            
42
18
  TRY_ASSERT_MAIN_THREAD { parseResponse(*response); }
43
18
  END_TRY
44
18
  catch (EnvoyException& e) {
45
    onFetchFailure(Config::ConfigUpdateFailureReason::UpdateRejected, &e);
46
  }
47

            
48
18
  requestComplete();
49
18
}
50

            
51
void RestApiFetcher::onFailure(const Http::AsyncClient::Request&,
52
1
                               Http::AsyncClient::FailureReason reason) {
53
1
  ASSERT(reason == Http::AsyncClient::FailureReason::Reset ||
54
1
         reason == Http::AsyncClient::FailureReason::ExceedResponseBufferLimit);
55
1
  onFetchFailure(Config::ConfigUpdateFailureReason::ConnectionFailure, nullptr);
56
1
  requestComplete();
57
1
}
58

            
59
39
void RestApiFetcher::refresh() {
60
39
  RequestMessagePtr message(new RequestMessageImpl());
61
39
  createRequest(*message);
62
39
  message->headers().setHost(remote_cluster_name_);
63
39
  const auto thread_local_cluster = cm_.getThreadLocalCluster(remote_cluster_name_);
64
39
  if (thread_local_cluster != nullptr) {
65
38
    active_request_ = thread_local_cluster->httpAsyncClient().send(
66
38
        std::move(message), *this, AsyncClient::RequestOptions().setTimeout(request_timeout_));
67
38
  } else {
68
1
    onFetchFailure(Config::ConfigUpdateFailureReason::ConnectionFailure, nullptr);
69
1
    requestComplete();
70
1
  }
71
39
}
72

            
73
21
void RestApiFetcher::requestComplete() {
74
21
  onFetchComplete();
75
21
  active_request_ = nullptr;
76

            
77
  // Add refresh jitter based on the configured interval.
78
21
  std::chrono::milliseconds final_delay =
79
21
      refresh_interval_ + std::chrono::milliseconds(random_.random() % refresh_interval_.count());
80

            
81
21
  refresh_timer_->enableTimer(final_delay);
82
21
}
83

            
84
} // namespace Http
85
} // namespace Envoy