Line data Source code
1 : #include "source/common/router/shadow_writer_impl.h" 2 : 3 : #include <chrono> 4 : #include <string> 5 : 6 : #include "source/common/common/assert.h" 7 : #include "source/common/http/headers.h" 8 : 9 : #include "absl/strings/str_join.h" 10 : 11 : namespace Envoy { 12 : namespace Router { 13 : 14 : namespace { 15 : 16 0 : std::string shadowAppendedHost(absl::string_view host) { 17 0 : ASSERT(!host.empty()); 18 : // Switch authority to add a shadow postfix. This allows upstream logging to 19 : // make more sense. 20 0 : auto parts = StringUtil::splitToken(host, ":"); 21 0 : ASSERT(!parts.empty() && parts.size() <= 2); 22 0 : return parts.size() == 2 ? absl::StrJoin(parts, "-shadow:") : absl::StrCat(host, "-shadow"); 23 0 : } 24 : 25 : } // namespace 26 : 27 : void ShadowWriterImpl::shadow(const std::string& cluster, Http::RequestMessagePtr&& request, 28 0 : const Http::AsyncClient::RequestOptions& options) { 29 0 : const auto thread_local_cluster = 30 0 : getClusterAndPreprocessHeadersAndOptions(cluster, request->headers(), options); 31 0 : if (thread_local_cluster == nullptr) { 32 0 : return; 33 0 : } 34 : // This is basically fire and forget. We don't handle cancelling. 35 0 : thread_local_cluster->httpAsyncClient().send(std::move(request), *this, options); 36 0 : } 37 : 38 : Http::AsyncClient::OngoingRequest* 39 : ShadowWriterImpl::streamingShadow(const std::string& cluster, Http::RequestHeaderMapPtr&& headers, 40 0 : const Http::AsyncClient::RequestOptions& options) { 41 0 : const auto thread_local_cluster = 42 0 : getClusterAndPreprocessHeadersAndOptions(cluster, *headers, options); 43 0 : if (thread_local_cluster == nullptr) { 44 0 : return nullptr; 45 0 : } 46 0 : return thread_local_cluster->httpAsyncClient().startRequest(std::move(headers), *this, options); 47 0 : } 48 : 49 : Upstream::ThreadLocalCluster* ShadowWriterImpl::getClusterAndPreprocessHeadersAndOptions( 50 : absl::string_view cluster, Http::RequestHeaderMap& headers, 51 0 : const Http::AsyncClient::RequestOptions& options) { 52 : // It's possible that the cluster specified in the route configuration no longer exists due 53 : // to a CDS removal. Check that it still exists before shadowing. 54 : // TODO(mattklein123): Optimally we would have a stat but for now just fix the crashing issue. 55 0 : const auto thread_local_cluster = cm_.getThreadLocalCluster(cluster); 56 0 : if (thread_local_cluster == nullptr) { 57 0 : ENVOY_LOG(debug, "shadow cluster '{}' does not exist", cluster); 58 0 : return nullptr; 59 0 : } 60 : 61 0 : headers.setHost(shadowAppendedHost(headers.getHostValue())); 62 : 63 0 : const_cast<Http::AsyncClient::RequestOptions&>(options).setIsShadow(true); 64 0 : return thread_local_cluster; 65 0 : } 66 : 67 : } // namespace Router 68 : } // namespace Envoy