/proc/self/cwd/source/common/stream_info/utility.cc
Line | Count | Source (jump to first uncovered line) |
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 | 31 | const std::string ResponseFlagUtils::toString(const StreamInfo& stream_info) { |
16 | 31 | return toString(stream_info, true); |
17 | 31 | } |
18 | | |
19 | 8.17k | const std::string ResponseFlagUtils::toShortString(const StreamInfo& stream_info) { |
20 | 8.17k | return toString(stream_info, false); |
21 | 8.17k | } |
22 | | |
23 | 8.20k | 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 | 8.20k | absl::InlinedVector<absl::string_view, 16> flag_strings_vec; |
27 | 213k | for (const auto& [flag_strings, flag] : ALL_RESPONSE_STRINGS_FLAGS) { |
28 | 213k | if (stream_info.hasResponseFlag(flag)) { |
29 | 576 | flag_strings_vec.push_back(use_long_name ? flag_strings.long_string_ |
30 | 576 | : flag_strings.short_string_); |
31 | 576 | } |
32 | 213k | } |
33 | 8.20k | if (flag_strings_vec.empty()) { |
34 | 7.63k | return std::string(NONE); |
35 | 7.63k | } |
36 | 576 | return absl::StrJoin(flag_strings_vec, ","); |
37 | 8.20k | } |
38 | | |
39 | 4 | absl::flat_hash_map<std::string, ResponseFlag> ResponseFlagUtils::getFlagMap() { |
40 | 4 | static_assert(ResponseFlag::LastFlag == 0x4000000, |
41 | 4 | "A flag has been added. Add the new flag to ALL_RESPONSE_STRINGS_FLAGS."); |
42 | 4 | absl::flat_hash_map<std::string, ResponseFlag> res; |
43 | 104 | for (auto [flag_strings, flag] : ResponseFlagUtils::ALL_RESPONSE_STRINGS_FLAGS) { |
44 | 104 | res.emplace(flag_strings.short_string_, flag); |
45 | 104 | } |
46 | 4 | return res; |
47 | 4 | } |
48 | | |
49 | 20.9k | absl::optional<ResponseFlag> ResponseFlagUtils::toResponseFlag(absl::string_view flag) { |
50 | | // This `MapType` is introduce because CONSTRUCT_ON_FIRST_USE doesn't like template. |
51 | 20.9k | using MapType = absl::flat_hash_map<std::string, ResponseFlag>; |
52 | 20.9k | const auto& flag_map = []() { |
53 | 20.9k | CONSTRUCT_ON_FIRST_USE(MapType, ResponseFlagUtils::getFlagMap()); |
54 | 20.9k | }(); |
55 | 20.9k | const auto& it = flag_map.find(flag); |
56 | 20.9k | if (it != flag_map.end()) { |
57 | 20.9k | return absl::make_optional<ResponseFlag>(it->second); |
58 | 20.9k | } |
59 | 0 | return absl::nullopt; |
60 | 20.9k | } |
61 | | |
62 | 2.60k | OptRef<const UpstreamTiming> getUpstreamTiming(const StreamInfo& stream_info) { |
63 | 2.60k | OptRef<const UpstreamInfo> info = stream_info.upstreamInfo(); |
64 | 2.60k | if (!info.has_value()) { |
65 | 273 | return {}; |
66 | 273 | } |
67 | 2.33k | return info.value().get().upstreamTiming(); |
68 | 2.60k | } |
69 | | |
70 | | absl::optional<std::chrono::nanoseconds> duration(const absl::optional<MonotonicTime>& time, |
71 | 3.71k | const StreamInfo& stream_info) { |
72 | 3.71k | if (!time.has_value()) { |
73 | 3.67k | return absl::nullopt; |
74 | 3.67k | } |
75 | 34 | return std::chrono::duration_cast<std::chrono::nanoseconds>(time.value() - |
76 | 34 | stream_info.startTimeMonotonic()); |
77 | 3.71k | } |
78 | | |
79 | 17 | absl::optional<std::chrono::nanoseconds> TimingUtility::firstUpstreamTxByteSent() { |
80 | 17 | OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_); |
81 | 17 | if (!timing) { |
82 | 17 | return absl::nullopt; |
83 | 17 | } |
84 | 0 | return duration(timing.value().get().first_upstream_tx_byte_sent_, stream_info_); |
85 | 17 | } |
86 | | |
87 | 888 | absl::optional<std::chrono::nanoseconds> TimingUtility::lastUpstreamTxByteSent() { |
88 | 888 | OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_); |
89 | 888 | if (!timing) { |
90 | 222 | return absl::nullopt; |
91 | 222 | } |
92 | 666 | return duration(timing.value().get().last_upstream_tx_byte_sent_, stream_info_); |
93 | 888 | } |
94 | | |
95 | 1.68k | absl::optional<std::chrono::nanoseconds> TimingUtility::firstUpstreamRxByteReceived() { |
96 | 1.68k | OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_); |
97 | 1.68k | if (!timing) { |
98 | 17 | return absl::nullopt; |
99 | 17 | } |
100 | 1.66k | return duration(timing.value().get().first_upstream_rx_byte_received_, stream_info_); |
101 | 1.68k | } |
102 | | |
103 | 17 | absl::optional<std::chrono::nanoseconds> TimingUtility::lastUpstreamRxByteReceived() { |
104 | 17 | OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_); |
105 | 17 | if (!timing) { |
106 | 17 | return absl::nullopt; |
107 | 17 | } |
108 | 0 | return duration(timing.value().get().last_upstream_rx_byte_received_, stream_info_); |
109 | 17 | } |
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 | 17 | absl::optional<std::chrono::nanoseconds> TimingUtility::firstDownstreamTxByteSent() { |
120 | 17 | OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming(); |
121 | 17 | if (!timing) { |
122 | 0 | return absl::nullopt; |
123 | 0 | } |
124 | 17 | return duration(timing.value().get().firstDownstreamTxByteSent(), stream_info_); |
125 | 17 | } |
126 | | |
127 | 1.39k | absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamTxByteSent() { |
128 | 1.39k | OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming(); |
129 | 1.39k | if (!timing) { |
130 | 1.31k | return absl::nullopt; |
131 | 1.31k | } |
132 | 83 | return duration(timing.value().get().lastDownstreamTxByteSent(), stream_info_); |
133 | 1.39k | } |
134 | | |
135 | 1.30k | absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamRxByteReceived() { |
136 | 1.30k | OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming(); |
137 | 1.30k | if (!timing) { |
138 | 257 | return absl::nullopt; |
139 | 257 | } |
140 | 1.05k | return duration(timing.value().get().lastDownstreamRxByteReceived(), stream_info_); |
141 | 1.30k | } |
142 | | |
143 | 573 | absl::optional<std::chrono::nanoseconds> TimingUtility::downstreamHandshakeComplete() { |
144 | 573 | OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming(); |
145 | 573 | if (!timing) { |
146 | 377 | return absl::nullopt; |
147 | 377 | } |
148 | 196 | return duration(timing.value().get().downstreamHandshakeComplete(), stream_info_); |
149 | 573 | } |
150 | | |
151 | 101 | absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamAckReceived() { |
152 | 101 | OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming(); |
153 | 101 | if (!timing) { |
154 | 66 | return absl::nullopt; |
155 | 66 | } |
156 | 35 | return duration(timing.value().get().lastDownstreamAckReceived(), stream_info_); |
157 | 101 | } |
158 | | |
159 | | const std::string& |
160 | 4.51k | Utility::formatDownstreamAddressNoPort(const Network::Address::Instance& address) { |
161 | 4.51k | if (address.type() == Network::Address::Type::Ip) { |
162 | 4.26k | return address.ip()->addressAsString(); |
163 | 4.26k | } else { |
164 | 247 | return address.asString(); |
165 | 247 | } |
166 | 4.51k | } |
167 | | |
168 | | const std::string |
169 | 14.8k | Utility::formatDownstreamAddressJustPort(const Network::Address::Instance& address) { |
170 | 14.8k | std::string port; |
171 | 14.8k | if (address.type() == Network::Address::Type::Ip) { |
172 | 14.3k | port = std::to_string(address.ip()->port()); |
173 | 14.3k | } |
174 | 14.8k | return port; |
175 | 14.8k | } |
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 | 11.7k | ProxyStatusConfig* proxy_status_config) { |
239 | 11.7k | if (proxy_status_config == nullptr) { |
240 | 11.3k | return std::string(server_name); |
241 | 11.3k | } |
242 | | // For the proxy name, the config specified either a preset proxy name or a literal proxy name. |
243 | 413 | switch (proxy_status_config->proxy_name_case()) { |
244 | 63 | case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager:: |
245 | 63 | ProxyStatusConfig::ProxyNameCase::kLiteralProxyName: { |
246 | 63 | return std::string(proxy_status_config->literal_proxy_name()); |
247 | 0 | } |
248 | 97 | case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager:: |
249 | 97 | ProxyStatusConfig::ProxyNameCase::kUseNodeId: { |
250 | 97 | return std::string(node_id); |
251 | 0 | } |
252 | 253 | case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager:: |
253 | 253 | ProxyStatusConfig::ProxyNameCase::PROXY_NAME_NOT_SET: |
254 | 253 | default: { |
255 | 253 | return std::string(server_name); |
256 | 253 | } |
257 | 413 | } |
258 | 413 | } |
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 | 149 | 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 | 149 | if (stream_info.hasResponseFlag(ResponseFlag::FailedLocalHealthCheck)) { |
366 | 0 | return ProxyStatusError::DestinationUnavailable; |
367 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::NoHealthyUpstream)) { |
368 | 0 | return ProxyStatusError::DestinationUnavailable; |
369 | 149 | } 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 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::LocalReset)) { |
376 | 0 | return ProxyStatusError::ConnectionTimeout; |
377 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamRemoteReset)) { |
378 | 0 | return ProxyStatusError::ConnectionTerminated; |
379 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamConnectionFailure)) { |
380 | 0 | return ProxyStatusError::ConnectionRefused; |
381 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamConnectionTermination)) { |
382 | 0 | return ProxyStatusError::ConnectionTerminated; |
383 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamOverflow)) { |
384 | 0 | return ProxyStatusError::ConnectionLimitReached; |
385 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::NoRouteFound)) { |
386 | 0 | return ProxyStatusError::DestinationNotFound; |
387 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::RateLimited)) { |
388 | 0 | return ProxyStatusError::ConnectionLimitReached; |
389 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::RateLimitServiceError)) { |
390 | 0 | return ProxyStatusError::ConnectionLimitReached; |
391 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamRetryLimitExceeded)) { |
392 | 0 | return ProxyStatusError::DestinationUnavailable; |
393 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::StreamIdleTimeout)) { |
394 | 0 | return ProxyStatusError::HttpResponseTimeout; |
395 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::InvalidEnvoyRequestHeaders)) { |
396 | 0 | return ProxyStatusError::HttpRequestError; |
397 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::DownstreamProtocolError)) { |
398 | 0 | return ProxyStatusError::HttpRequestError; |
399 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamMaxStreamDurationReached)) { |
400 | 0 | return ProxyStatusError::HttpResponseTimeout; |
401 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::NoFilterConfigFound)) { |
402 | 0 | return ProxyStatusError::ProxyConfigurationError; |
403 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::UpstreamProtocolError)) { |
404 | 0 | return ProxyStatusError::HttpProtocolError; |
405 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::NoClusterFound)) { |
406 | 0 | return ProxyStatusError::DestinationUnavailable; |
407 | 149 | } else if (stream_info.hasResponseFlag(ResponseFlag::DnsResolutionFailed)) { |
408 | 0 | return ProxyStatusError::DnsError; |
409 | 149 | } else { |
410 | 149 | return absl::nullopt; |
411 | 149 | } |
412 | 149 | } |
413 | | |
414 | | } // namespace StreamInfo |
415 | | } // namespace Envoy |