Line data Source code
1 : #include "source/common/config/remote_data_fetcher.h" 2 : 3 : #include "envoy/config/core/v3/http_uri.pb.h" 4 : 5 : #include "source/common/common/enum_to_int.h" 6 : #include "source/common/common/hex.h" 7 : #include "source/common/crypto/utility.h" 8 : #include "source/common/http/headers.h" 9 : #include "source/common/http/utility.h" 10 : 11 : namespace Envoy { 12 : namespace Config { 13 : namespace DataFetcher { 14 : 15 : RemoteDataFetcher::RemoteDataFetcher(Upstream::ClusterManager& cm, 16 : const envoy::config::core::v3::HttpUri& uri, 17 : const std::string& content_hash, 18 : RemoteDataFetcherCallback& callback) 19 0 : : cm_(cm), uri_(uri), content_hash_(content_hash), callback_(callback) {} 20 : 21 0 : RemoteDataFetcher::~RemoteDataFetcher() { cancel(); } 22 : 23 0 : void RemoteDataFetcher::cancel() { 24 0 : if (request_) { 25 0 : request_->cancel(); 26 0 : ENVOY_LOG(debug, "fetch remote data [uri = {}]: canceled", uri_.uri()); 27 0 : } 28 : 29 0 : request_ = nullptr; 30 0 : } 31 : 32 0 : void RemoteDataFetcher::fetch() { 33 0 : Http::RequestMessagePtr message = Http::Utility::prepareHeaders(uri_); 34 0 : message->headers().setReferenceMethod(Http::Headers::get().MethodValues.Get); 35 0 : ENVOY_LOG(debug, "fetch remote data from [uri = {}]: start", uri_.uri()); 36 0 : const auto thread_local_cluster = cm_.getThreadLocalCluster(uri_.cluster()); 37 0 : if (thread_local_cluster != nullptr) { 38 0 : request_ = thread_local_cluster->httpAsyncClient().send( 39 0 : std::move(message), *this, 40 0 : Http::AsyncClient::RequestOptions().setTimeout( 41 0 : std::chrono::milliseconds(DurationUtil::durationToMilliseconds(uri_.timeout())))); 42 0 : } else { 43 0 : ENVOY_LOG(debug, "fetch remote data [uri = {}]: no cluster {}", uri_.uri(), uri_.cluster()); 44 0 : callback_.onFailure(FailureReason::Network); 45 0 : } 46 0 : } 47 : 48 : void RemoteDataFetcher::onSuccess(const Http::AsyncClient::Request&, 49 0 : Http::ResponseMessagePtr&& response) { 50 0 : const uint64_t status_code = Http::Utility::getResponseStatus(response->headers()); 51 0 : if (status_code == enumToInt(Http::Code::OK)) { 52 0 : ENVOY_LOG(debug, "fetch remote data [uri = {}]: success", uri_.uri()); 53 0 : if (response->body().length() > 0) { 54 0 : auto& crypto_util = Envoy::Common::Crypto::UtilitySingleton::get(); 55 0 : const auto content_hash = Hex::encode(crypto_util.getSha256Digest(response->body())); 56 : 57 0 : if (content_hash_ != content_hash) { 58 0 : ENVOY_LOG(debug, "fetch remote data [uri = {}]: data is invalid", uri_.uri()); 59 0 : callback_.onFailure(FailureReason::InvalidData); 60 0 : } else { 61 0 : callback_.onSuccess(response->bodyAsString()); 62 0 : } 63 0 : } else { 64 0 : ENVOY_LOG(debug, "fetch remote data [uri = {}]: body is empty", uri_.uri()); 65 0 : callback_.onFailure(FailureReason::Network); 66 0 : } 67 0 : } else { 68 0 : ENVOY_LOG(debug, "fetch remote data [uri = {}]: response status code {}", uri_.uri(), 69 0 : status_code); 70 0 : callback_.onFailure(FailureReason::Network); 71 0 : } 72 : 73 0 : request_ = nullptr; 74 0 : } 75 : 76 : void RemoteDataFetcher::onFailure(const Http::AsyncClient::Request&, 77 0 : Http::AsyncClient::FailureReason reason) { 78 0 : ENVOY_LOG(debug, "fetch remote data [uri = {}]: network error {}", uri_.uri(), enumToInt(reason)); 79 0 : request_ = nullptr; 80 0 : callback_.onFailure(FailureReason::Network); 81 0 : } 82 : 83 : } // namespace DataFetcher 84 : } // namespace Config 85 : } // namespace Envoy