LCOV - code coverage report
Current view: top level - source/common/stream_info - utility.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 42 344 12.2 %
Date: 2024-01-05 06:35:25 Functions: 7 26 26.9 %

          Line data    Source code
       1             : #include "source/common/stream_info/utility.h"
       2             : 
       3             : #include <string>
       4             : 
       5             : #include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"
       6             : 
       7             : #include "source/common/http/default_server_string.h"
       8             : #include "source/common/runtime/runtime_features.h"
       9             : 
      10             : #include "absl/strings/str_format.h"
      11             : 
      12             : namespace Envoy {
      13             : namespace StreamInfo {
      14             : 
      15           0 : const std::string ResponseFlagUtils::toString(const StreamInfo& stream_info) {
      16           0 :   return toString(stream_info, true);
      17           0 : }
      18             : 
      19         612 : const std::string ResponseFlagUtils::toShortString(const StreamInfo& stream_info) {
      20         612 :   return toString(stream_info, false);
      21         612 : }
      22             : 
      23         612 : const std::string ResponseFlagUtils::toString(const StreamInfo& stream_info, bool use_long_name) {
      24             :   // We don't expect more than 4 flags are set. Relax to 16 since the vector is allocated on stack
      25             :   // anyway.
      26         612 :   absl::InlinedVector<absl::string_view, 16> flag_strings_vec;
      27       17136 :   for (const auto& [flag_strings, flag] : ALL_RESPONSE_STRINGS_FLAGS) {
      28       17136 :     if (stream_info.hasResponseFlag(flag)) {
      29         244 :       flag_strings_vec.push_back(use_long_name ? flag_strings.long_string_
      30         244 :                                                : flag_strings.short_string_);
      31         244 :     }
      32       17136 :   }
      33         612 :   if (flag_strings_vec.empty()) {
      34         368 :     return std::string(NONE);
      35         368 :   }
      36         244 :   return absl::StrJoin(flag_strings_vec, ",");
      37         612 : }
      38             : 
      39           0 : absl::flat_hash_map<std::string, ResponseFlag> ResponseFlagUtils::getFlagMap() {
      40           0 :   static_assert(ResponseFlag::LastFlag == 0x8000000,
      41           0 :                 "A flag has been added. Add the new flag to ALL_RESPONSE_STRINGS_FLAGS.");
      42           0 :   absl::flat_hash_map<std::string, ResponseFlag> res;
      43           0 :   for (auto [flag_strings, flag] : ResponseFlagUtils::ALL_RESPONSE_STRINGS_FLAGS) {
      44           0 :     res.emplace(flag_strings.short_string_, flag);
      45           0 :   }
      46           0 :   return res;
      47           0 : }
      48             : 
      49           0 : absl::optional<ResponseFlag> ResponseFlagUtils::toResponseFlag(absl::string_view flag) {
      50             :   // This `MapType` is introduce because CONSTRUCT_ON_FIRST_USE doesn't like template.
      51           0 :   using MapType = absl::flat_hash_map<std::string, ResponseFlag>;
      52           0 :   const auto& flag_map = []() {
      53           0 :     CONSTRUCT_ON_FIRST_USE(MapType, ResponseFlagUtils::getFlagMap());
      54           0 :   }();
      55           0 :   const auto& it = flag_map.find(flag);
      56           0 :   if (it != flag_map.end()) {
      57           0 :     return absl::make_optional<ResponseFlag>(it->second);
      58           0 :   }
      59           0 :   return absl::nullopt;
      60           0 : }
      61             : 
      62           3 : OptRef<const UpstreamTiming> getUpstreamTiming(const StreamInfo& stream_info) {
      63           3 :   OptRef<const UpstreamInfo> info = stream_info.upstreamInfo();
      64           3 :   if (!info.has_value()) {
      65           0 :     return {};
      66           0 :   }
      67           3 :   return info.value().get().upstreamTiming();
      68           3 : }
      69             : 
      70             : absl::optional<std::chrono::nanoseconds> duration(const absl::optional<MonotonicTime>& time,
      71           3 :                                                   const StreamInfo& stream_info) {
      72           3 :   if (!time.has_value()) {
      73           3 :     return absl::nullopt;
      74           3 :   }
      75           0 :   return std::chrono::duration_cast<std::chrono::nanoseconds>(time.value() -
      76           0 :                                                               stream_info.startTimeMonotonic());
      77           3 : }
      78             : 
      79           0 : absl::optional<std::chrono::nanoseconds> TimingUtility::firstUpstreamTxByteSent() {
      80           0 :   OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_);
      81           0 :   if (!timing) {
      82           0 :     return absl::nullopt;
      83           0 :   }
      84           0 :   return duration(timing.value().get().first_upstream_tx_byte_sent_, stream_info_);
      85           0 : }
      86             : 
      87           3 : absl::optional<std::chrono::nanoseconds> TimingUtility::lastUpstreamTxByteSent() {
      88           3 :   OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_);
      89           3 :   if (!timing) {
      90           0 :     return absl::nullopt;
      91           0 :   }
      92           3 :   return duration(timing.value().get().last_upstream_tx_byte_sent_, stream_info_);
      93           3 : }
      94             : 
      95           0 : absl::optional<std::chrono::nanoseconds> TimingUtility::firstUpstreamRxByteReceived() {
      96           0 :   OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_);
      97           0 :   if (!timing) {
      98           0 :     return absl::nullopt;
      99           0 :   }
     100           0 :   return duration(timing.value().get().first_upstream_rx_byte_received_, stream_info_);
     101           0 : }
     102             : 
     103           0 : absl::optional<std::chrono::nanoseconds> TimingUtility::lastUpstreamRxByteReceived() {
     104           0 :   OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_);
     105           0 :   if (!timing) {
     106           0 :     return absl::nullopt;
     107           0 :   }
     108           0 :   return duration(timing.value().get().last_upstream_rx_byte_received_, stream_info_);
     109           0 : }
     110             : 
     111           0 : absl::optional<std::chrono::nanoseconds> TimingUtility::upstreamHandshakeComplete() {
     112           0 :   OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_);
     113           0 :   if (!timing) {
     114           0 :     return absl::nullopt;
     115           0 :   }
     116           0 :   return duration(timing.value().get().upstreamHandshakeComplete(), stream_info_);
     117           0 : }
     118             : 
     119           0 : absl::optional<std::chrono::nanoseconds> TimingUtility::firstDownstreamTxByteSent() {
     120           0 :   OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming();
     121           0 :   if (!timing) {
     122           0 :     return absl::nullopt;
     123           0 :   }
     124           0 :   return duration(timing.value().get().firstDownstreamTxByteSent(), stream_info_);
     125           0 : }
     126             : 
     127           0 : absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamTxByteSent() {
     128           0 :   OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming();
     129           0 :   if (!timing) {
     130           0 :     return absl::nullopt;
     131           0 :   }
     132           0 :   return duration(timing.value().get().lastDownstreamTxByteSent(), stream_info_);
     133           0 : }
     134             : 
     135           0 : absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamRxByteReceived() {
     136           0 :   OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming();
     137           0 :   if (!timing) {
     138           0 :     return absl::nullopt;
     139           0 :   }
     140           0 :   return duration(timing.value().get().lastDownstreamRxByteReceived(), stream_info_);
     141           0 : }
     142             : 
     143           0 : absl::optional<std::chrono::nanoseconds> TimingUtility::downstreamHandshakeComplete() {
     144           0 :   OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming();
     145           0 :   if (!timing) {
     146           0 :     return absl::nullopt;
     147           0 :   }
     148           0 :   return duration(timing.value().get().downstreamHandshakeComplete(), stream_info_);
     149           0 : }
     150             : 
     151           0 : absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamAckReceived() {
     152           0 :   OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming();
     153           0 :   if (!timing) {
     154           0 :     return absl::nullopt;
     155           0 :   }
     156           0 :   return duration(timing.value().get().lastDownstreamAckReceived(), stream_info_);
     157           0 : }
     158             : 
     159             : const std::string&
     160          56 : Utility::formatDownstreamAddressNoPort(const Network::Address::Instance& address) {
     161          56 :   if (address.type() == Network::Address::Type::Ip) {
     162           3 :     return address.ip()->addressAsString();
     163          53 :   } else {
     164          53 :     return address.asString();
     165          53 :   }
     166          56 : }
     167             : 
     168             : const std::string
     169           0 : Utility::formatDownstreamAddressJustPort(const Network::Address::Instance& address) {
     170           0 :   std::string port;
     171           0 :   if (address.type() == Network::Address::Type::Ip) {
     172           0 :     port = std::to_string(address.ip()->port());
     173           0 :   }
     174           0 :   return port;
     175           0 : }
     176             : 
     177             : absl::optional<uint32_t>
     178           0 : Utility::extractDownstreamAddressJustPort(const Network::Address::Instance& address) {
     179           0 :   if (address.type() == Network::Address::Type::Ip) {
     180           0 :     return address.ip()->port();
     181           0 :   }
     182           0 :   return {};
     183           0 : }
     184             : 
     185             : const absl::optional<Http::Code>
     186           0 : ProxyStatusUtils::recommendedHttpStatusCode(const ProxyStatusError proxy_status) {
     187             :   // This switch statement was derived from the mapping from proxy error type to
     188             :   // recommended HTTP status code in
     189             :   // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-proxy-status-05#section-2.3 and below.
     190             :   //
     191             :   // TODO(ambuc): Replace this with the non-draft URL when finalized.
     192           0 :   switch (proxy_status) {
     193           0 :   case ProxyStatusError::DnsTimeout:
     194           0 :   case ProxyStatusError::ConnectionTimeout:
     195           0 :   case ProxyStatusError::ConnectionReadTimeout:
     196           0 :   case ProxyStatusError::ConnectionWriteTimeout:
     197           0 :   case ProxyStatusError::HttpResponseTimeout:
     198           0 :     return Http::Code::GatewayTimeout; // 504
     199           0 :   case ProxyStatusError::DnsError:
     200           0 :   case ProxyStatusError::DestinationIpProhibited:
     201           0 :   case ProxyStatusError::DestinationIpUnroutable:
     202           0 :   case ProxyStatusError::ConnectionRefused:
     203           0 :   case ProxyStatusError::ConnectionTerminated:
     204           0 :   case ProxyStatusError::TlsProtocolError:
     205           0 :   case ProxyStatusError::TlsCertificateError:
     206           0 :   case ProxyStatusError::TlsAlertReceived:
     207           0 :   case ProxyStatusError::HttpResponseIncomplete:
     208           0 :   case ProxyStatusError::HttpResponseHeaderSectionSize:
     209           0 :   case ProxyStatusError::HttpResponseHeaderSize:
     210           0 :   case ProxyStatusError::HttpResponseBodySize:
     211           0 :   case ProxyStatusError::HttpResponseTrailerSectionSize:
     212           0 :   case ProxyStatusError::HttpResponseTrailerSize:
     213           0 :   case ProxyStatusError::HttpResponseTransferCoding:
     214           0 :   case ProxyStatusError::HttpResponseContentCoding:
     215           0 :   case ProxyStatusError::HttpUpgradeFailed:
     216           0 :   case ProxyStatusError::HttpProtocolError:
     217           0 :   case ProxyStatusError::ProxyLoopDetected:
     218           0 :     return Http::Code::BadGateway; // 502
     219           0 :   case ProxyStatusError::DestinationNotFound:
     220           0 :   case ProxyStatusError::ProxyInternalError:
     221           0 :   case ProxyStatusError::ProxyConfigurationError:
     222           0 :     return Http::Code::InternalServerError; // 500
     223           0 :   case ProxyStatusError::DestinationUnavailable:
     224           0 :   case ProxyStatusError::ConnectionLimitReached:
     225           0 :     return Http::Code::ServiceUnavailable; // 503
     226           0 :   case ProxyStatusError::HttpRequestDenied:
     227           0 :     return Http::Code::Forbidden; // 403
     228           0 :   case ProxyStatusError::ProxyInternalResponse:
     229           0 :   case ProxyStatusError::HttpRequestError:
     230           0 :   default:
     231           0 :     return absl::nullopt;
     232           0 :   }
     233           0 : }
     234             : 
     235             : const std::string ProxyStatusUtils::makeProxyName(
     236             :     absl::string_view node_id, absl::string_view server_name,
     237             :     const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
     238         922 :         ProxyStatusConfig* proxy_status_config) {
     239         922 :   if (proxy_status_config == nullptr) {
     240         922 :     return std::string(server_name);
     241         922 :   }
     242             :   // For the proxy name, the config specified either a preset proxy name or a literal proxy name.
     243           0 :   switch (proxy_status_config->proxy_name_case()) {
     244           0 :   case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
     245           0 :       ProxyStatusConfig::ProxyNameCase::kLiteralProxyName: {
     246           0 :     return std::string(proxy_status_config->literal_proxy_name());
     247           0 :   }
     248           0 :   case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
     249           0 :       ProxyStatusConfig::ProxyNameCase::kUseNodeId: {
     250           0 :     return std::string(node_id);
     251           0 :   }
     252           0 :   case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
     253           0 :       ProxyStatusConfig::ProxyNameCase::PROXY_NAME_NOT_SET:
     254           0 :   default: {
     255           0 :     return std::string(server_name);
     256           0 :   }
     257           0 :   }
     258           0 : }
     259             : 
     260             : const std::string ProxyStatusUtils::makeProxyStatusHeader(
     261             :     const StreamInfo& stream_info, const ProxyStatusError error, absl::string_view proxy_name,
     262             :     const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
     263           0 :         ProxyStatusConfig& proxy_status_config) {
     264           0 :   std::vector<std::string> retval = {};
     265             : 
     266           0 :   retval.push_back(std::string(proxy_name));
     267             : 
     268           0 :   retval.push_back(absl::StrFormat("error=%s", proxyStatusErrorToString(error)));
     269             : 
     270           0 :   if (!proxy_status_config.remove_details() && stream_info.responseCodeDetails().has_value()) {
     271           0 :     std::vector<std::string> details = {};
     272           0 :     details.push_back(stream_info.responseCodeDetails().value());
     273           0 :     if (!proxy_status_config.remove_connection_termination_details() &&
     274           0 :         stream_info.connectionTerminationDetails().has_value()) {
     275           0 :       details.push_back(stream_info.connectionTerminationDetails().value());
     276           0 :     }
     277           0 :     if (!proxy_status_config.remove_response_flags() && stream_info.hasAnyResponseFlag()) {
     278           0 :       details.push_back(ResponseFlagUtils::toShortString(stream_info));
     279           0 :     }
     280           0 :     retval.push_back(
     281           0 :         absl::StrFormat("details=\"%s\"", StringUtil::escape(absl::StrJoin(details, "; "))));
     282           0 :   }
     283             : 
     284           0 :   return absl::StrJoin(retval, "; ");
     285           0 : }
     286             : 
     287             : const absl::string_view
     288           0 : ProxyStatusUtils::proxyStatusErrorToString(const ProxyStatusError proxy_status) {
     289           0 :   switch (proxy_status) {
     290           0 :   case ProxyStatusError::DnsTimeout:
     291           0 :     return DNS_TIMEOUT;
     292           0 :   case ProxyStatusError::DnsError:
     293           0 :     return DNS_ERROR;
     294           0 :   case ProxyStatusError::DestinationNotFound:
     295           0 :     return DESTINATION_NOT_FOUND;
     296           0 :   case ProxyStatusError::DestinationUnavailable:
     297           0 :     return DESTINATION_UNAVAILABLE;
     298           0 :   case ProxyStatusError::DestinationIpProhibited:
     299           0 :     return DESTINATION_IP_PROHIBITED;
     300           0 :   case ProxyStatusError::DestinationIpUnroutable:
     301           0 :     return DESTINATION_IP_UNROUTABLE;
     302           0 :   case ProxyStatusError::ConnectionRefused:
     303           0 :     return CONNECTION_REFUSED;
     304           0 :   case ProxyStatusError::ConnectionTerminated:
     305           0 :     return CONNECTION_TERMINATED;
     306           0 :   case ProxyStatusError::ConnectionTimeout:
     307           0 :     return CONNECTION_TIMEOUT;
     308           0 :   case ProxyStatusError::ConnectionReadTimeout:
     309           0 :     return CONNECTION_READ_TIMEOUT;
     310           0 :   case ProxyStatusError::ConnectionWriteTimeout:
     311           0 :     return CONNECTION_WRITE_TIMEOUT;
     312           0 :   case ProxyStatusError::ConnectionLimitReached:
     313           0 :     return CONNECTION_LIMIT_REACHED;
     314           0 :   case ProxyStatusError::TlsProtocolError:
     315           0 :     return TLS_PROTOCOL_ERROR;
     316           0 :   case ProxyStatusError::TlsCertificateError:
     317           0 :     return TLS_CERTIFICATE_ERROR;
     318           0 :   case ProxyStatusError::TlsAlertReceived:
     319           0 :     return TLS_ALERT_RECEIVED;
     320           0 :   case ProxyStatusError::HttpRequestError:
     321           0 :     return HTTP_REQUEST_ERROR;
     322           0 :   case ProxyStatusError::HttpRequestDenied:
     323           0 :     return HTTP_REQUEST_DENIED;
     324           0 :   case ProxyStatusError::HttpResponseIncomplete:
     325           0 :     return HTTP_RESPONSE_INCOMPLETE;
     326           0 :   case ProxyStatusError::HttpResponseHeaderSectionSize:
     327           0 :     return HTTP_RESPONSE_HEADER_SECTION_SIZE;
     328           0 :   case ProxyStatusError::HttpResponseHeaderSize:
     329           0 :     return HTTP_RESPONSE_HEADER_SIZE;
     330           0 :   case ProxyStatusError::HttpResponseBodySize:
     331           0 :     return HTTP_RESPONSE_BODY_SIZE;
     332           0 :   case ProxyStatusError::HttpResponseTrailerSectionSize:
     333           0 :     return HTTP_RESPONSE_TRAILER_SECTION_SIZE;
     334           0 :   case ProxyStatusError::HttpResponseTrailerSize:
     335           0 :     return HTTP_RESPONSE_TRAILER_SIZE;
     336           0 :   case ProxyStatusError::HttpResponseTransferCoding:
     337           0 :     return HTTP_RESPONSE_TRANSFER_CODING;
     338           0 :   case ProxyStatusError::HttpResponseContentCoding:
     339           0 :     return HTTP_RESPONSE_CONTENT_CODING;
     340           0 :   case ProxyStatusError::HttpResponseTimeout:
     341           0 :     return HTTP_RESPONSE_TIMEOUT;
     342           0 :   case ProxyStatusError::HttpUpgradeFailed:
     343           0 :     return HTTP_UPGRADE_FAILED;
     344           0 :   case ProxyStatusError::HttpProtocolError:
     345           0 :     return HTTP_PROTOCOL_ERROR;
     346           0 :   case ProxyStatusError::ProxyInternalResponse:
     347           0 :     return PROXY_INTERNAL_RESPONSE;
     348           0 :   case ProxyStatusError::ProxyInternalError:
     349           0 :     return PROXY_INTERNAL_ERROR;
     350           0 :   case ProxyStatusError::ProxyConfigurationError:
     351           0 :     return PROXY_CONFIGURATION_ERROR;
     352           0 :   case ProxyStatusError::ProxyLoopDetected:
     353           0 :     return PROXY_LOOP_DETECTED;
     354           0 :   default:
     355           0 :     return "-";
     356           0 :   }
     357           0 : }
     358             : 
     359             : const absl::optional<ProxyStatusError>
     360           0 : ProxyStatusUtils::fromStreamInfo(const StreamInfo& stream_info) {
     361             :   // NB: This mapping from Envoy-specific ResponseFlag enum to Proxy-Status
     362             :   // error enum is lossy, since ResponseFlag is really a bitset of many
     363             :   // ResponseFlag enums. Here, we search the list of all known ResponseFlag values in
     364             :   // enum order, returning the first matching ProxyStatusError.
     365           0 :   if (stream_info.hasResponseFlag(ResponseFlag::FailedLocalHealthCheck)) {
     366           0 :     return ProxyStatusError::DestinationUnavailable;
     367           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::NoHealthyUpstream)) {
     368           0 :     return ProxyStatusError::DestinationUnavailable;
     369           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamRequestTimeout)) {
     370           0 :     if (!Runtime::runtimeFeatureEnabled(
     371           0 :             "envoy.reloadable_features.proxy_status_upstream_request_timeout")) {
     372           0 :       return ProxyStatusError::ConnectionTimeout;
     373           0 :     }
     374           0 :     return ProxyStatusError::HttpResponseTimeout;
     375           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::LocalReset)) {
     376           0 :     return ProxyStatusError::ConnectionTimeout;
     377           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamRemoteReset)) {
     378           0 :     return ProxyStatusError::ConnectionTerminated;
     379           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamConnectionFailure)) {
     380           0 :     return ProxyStatusError::ConnectionRefused;
     381           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamConnectionTermination)) {
     382           0 :     return ProxyStatusError::ConnectionTerminated;
     383           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamOverflow)) {
     384           0 :     return ProxyStatusError::ConnectionLimitReached;
     385           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::NoRouteFound)) {
     386           0 :     return ProxyStatusError::DestinationNotFound;
     387           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::RateLimited)) {
     388           0 :     return ProxyStatusError::ConnectionLimitReached;
     389           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::RateLimitServiceError)) {
     390           0 :     return ProxyStatusError::ConnectionLimitReached;
     391           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamRetryLimitExceeded)) {
     392           0 :     return ProxyStatusError::DestinationUnavailable;
     393           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::StreamIdleTimeout)) {
     394           0 :     return ProxyStatusError::HttpResponseTimeout;
     395           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::InvalidEnvoyRequestHeaders)) {
     396           0 :     return ProxyStatusError::HttpRequestError;
     397           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::DownstreamProtocolError)) {
     398           0 :     return ProxyStatusError::HttpRequestError;
     399           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamMaxStreamDurationReached)) {
     400           0 :     return ProxyStatusError::HttpResponseTimeout;
     401           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::NoFilterConfigFound)) {
     402           0 :     return ProxyStatusError::ProxyConfigurationError;
     403           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamProtocolError)) {
     404           0 :     return ProxyStatusError::HttpProtocolError;
     405           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::NoClusterFound)) {
     406           0 :     return ProxyStatusError::DestinationUnavailable;
     407           0 :   } else if (stream_info.hasResponseFlag(ResponseFlag::DnsResolutionFailed)) {
     408           0 :     return ProxyStatusError::DnsError;
     409           0 :   } else {
     410           0 :     return absl::nullopt;
     411           0 :   }
     412           0 : }
     413             : 
     414             : } // namespace StreamInfo
     415             : } // namespace Envoy

Generated by: LCOV version 1.15