/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 | | namespace { |
16 | | |
17 | | // This flag is used to ensure that the responseFlagsVec() contains all the flags and no |
18 | | // any new custom flags are registered after the responseFlagsVec() is initialized. |
19 | | // NOTE: we expect all registrations of custom flags to happen during static initialization |
20 | | // before the first use of responseFlagsVec(). So no thread safety is needed here. |
21 | 18 | bool& responseFlagsVecInitialized() { MUTABLE_CONSTRUCT_ON_FIRST_USE(bool, false); } |
22 | | |
23 | | } // namespace |
24 | | |
25 | 0 | const std::string ResponseFlagUtils::toString(const StreamInfo& stream_info) { |
26 | 0 | return toString(stream_info, true); |
27 | 0 | } |
28 | | |
29 | 1.68k | const std::string ResponseFlagUtils::toShortString(const StreamInfo& stream_info) { |
30 | 1.68k | return toString(stream_info, false); |
31 | 1.68k | } |
32 | | |
33 | 1.68k | const std::string ResponseFlagUtils::toString(const StreamInfo& stream_info, bool use_long_name) { |
34 | | // We don't expect more than 4 flags are set. Relax to 16 since the vector is allocated on stack |
35 | | // anyway. |
36 | 1.68k | absl::InlinedVector<absl::string_view, 16> flag_strings_vec; |
37 | | |
38 | 1.68k | const auto& all_flag_strings = responseFlagsVec(); |
39 | 1.68k | for (const auto flag : stream_info.responseFlags()) { |
40 | 774 | ASSERT(flag.value() < all_flag_strings.size(), "Flag value out of range"); |
41 | | |
42 | 774 | const auto flag_strings = all_flag_strings[flag.value()]; |
43 | 774 | flag_strings_vec.push_back(use_long_name ? flag_strings.long_string_ |
44 | 774 | : flag_strings.short_string_); |
45 | 774 | } |
46 | 1.68k | if (flag_strings_vec.empty()) { |
47 | 912 | return std::string(NONE); |
48 | 912 | } |
49 | 774 | return absl::StrJoin(flag_strings_vec, ","); |
50 | 1.68k | } |
51 | | |
52 | 9.45k | ResponseFlagUtils::ResponseFlagsMapType& ResponseFlagUtils::mutableResponseFlagsMap() { |
53 | 9.45k | MUTABLE_CONSTRUCT_ON_FIRST_USE(ResponseFlagsMapType, []() { |
54 | 9.45k | ResponseFlagsMapType map; |
55 | | // Initialize the map with the all core flags first to ensure no custom flags |
56 | | // conflict with them. |
57 | 9.45k | RELEASE_ASSERT(CORE_RESPONSE_FLAGS.size() == CoreResponseFlag::LastFlag + 1, |
58 | 9.45k | "Not all inlined flags are contained by CORE_RESPONSE_FLAGS."); |
59 | | |
60 | 9.45k | map.reserve(CORE_RESPONSE_FLAGS.size()); |
61 | 9.45k | for (const auto& flag : CORE_RESPONSE_FLAGS) { |
62 | 9.45k | map.emplace(flag.short_string_, FlagLongString{flag.flag_, std::string(flag.long_string_)}); |
63 | 9.45k | } |
64 | 9.45k | RELEASE_ASSERT(map.size() == CORE_RESPONSE_FLAGS.size(), |
65 | 9.45k | "Duplicate flags in CORE_RESPONSE_FLAGS"); |
66 | 9.45k | return map; |
67 | 9.45k | }()); |
68 | 9.45k | } |
69 | | |
70 | | ResponseFlag ResponseFlagUtils::registerCustomFlag(absl::string_view custom_flag, |
71 | 0 | absl::string_view custom_flag_long) { |
72 | 0 | auto& mutable_flags = mutableResponseFlagsMap(); |
73 | |
|
74 | 0 | RELEASE_ASSERT(!responseFlagsVecInitialized(), |
75 | 0 | "Cannot register custom flags after initialization"); |
76 | | |
77 | 0 | RELEASE_ASSERT(!mutable_flags.contains(custom_flag), |
78 | 0 | fmt::format("Flag: {}/{} already registered", custom_flag, custom_flag_long)); |
79 | | |
80 | 0 | const uint16_t next_flag = mutable_flags.size(); |
81 | |
|
82 | 0 | mutable_flags.emplace(custom_flag, FlagLongString{next_flag, std::string(custom_flag_long)}); |
83 | |
|
84 | 0 | return next_flag; |
85 | 0 | } |
86 | | |
87 | 103k | const ResponseFlagUtils::ResponseFlagsVecType& ResponseFlagUtils::responseFlagsVec() { |
88 | 103k | CONSTRUCT_ON_FIRST_USE(ResponseFlagsVecType, []() { |
89 | 103k | static_assert(CoreResponseFlag::LastFlag == 28, |
90 | 103k | "A flag has been added. Add the new flag to CORE_RESPONSE_FLAGS."); |
91 | | |
92 | 103k | responseFlagsVecInitialized() = true; |
93 | | |
94 | 103k | ResponseFlagsVecType res; |
95 | | |
96 | 103k | uint16_t max_flag = CoreResponseFlag::LastFlag; |
97 | 103k | for (const auto& flag : responseFlagsMap()) { |
98 | 103k | if (flag.second.flag_.value() > max_flag) { |
99 | 103k | max_flag = flag.second.flag_.value(); |
100 | 103k | } |
101 | 103k | } |
102 | | |
103 | 103k | res.resize(max_flag + 1); |
104 | | |
105 | 103k | for (const auto& flag : responseFlagsMap()) { |
106 | 103k | res[flag.second.flag_.value()] = {absl::string_view(flag.first), |
107 | 103k | absl::string_view(flag.second.long_string_), |
108 | 103k | flag.second.flag_}; |
109 | 103k | } |
110 | | |
111 | 103k | return res; |
112 | 103k | }()); |
113 | 103k | } |
114 | | |
115 | 9.45k | const ResponseFlagUtils::ResponseFlagsMapType& ResponseFlagUtils::responseFlagsMap() { |
116 | 9.45k | return mutableResponseFlagsMap(); |
117 | 9.45k | } |
118 | | |
119 | 4.70k | absl::optional<ResponseFlag> ResponseFlagUtils::toResponseFlag(absl::string_view flag) { |
120 | 4.70k | const auto iter = responseFlagsMap().find(flag); |
121 | 4.70k | if (iter != responseFlagsMap().end()) { |
122 | 4.70k | return iter->second.flag_; |
123 | 4.70k | } |
124 | 0 | return absl::nullopt; |
125 | 4.70k | } |
126 | | |
127 | | CustomResponseFlag::CustomResponseFlag(absl::string_view flag, absl::string_view flag_long) |
128 | 0 | : flag_(ResponseFlagUtils::registerCustomFlag(flag, flag_long)) {} |
129 | | |
130 | 216 | OptRef<const UpstreamTiming> getUpstreamTiming(const StreamInfo& stream_info) { |
131 | 216 | OptRef<const UpstreamInfo> info = stream_info.upstreamInfo(); |
132 | 216 | if (!info.has_value()) { |
133 | 216 | return {}; |
134 | 216 | } |
135 | 0 | return info.value().get().upstreamTiming(); |
136 | 216 | } |
137 | | |
138 | | absl::optional<std::chrono::nanoseconds> duration(const absl::optional<MonotonicTime>& time, |
139 | 216 | const StreamInfo& stream_info) { |
140 | 216 | if (!time.has_value()) { |
141 | 108 | return absl::nullopt; |
142 | 108 | } |
143 | 108 | return std::chrono::duration_cast<std::chrono::nanoseconds>(time.value() - |
144 | 108 | stream_info.startTimeMonotonic()); |
145 | 216 | } |
146 | | |
147 | 54 | absl::optional<std::chrono::nanoseconds> TimingUtility::firstUpstreamTxByteSent() { |
148 | 54 | OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_); |
149 | 54 | if (!timing) { |
150 | 54 | return absl::nullopt; |
151 | 54 | } |
152 | 0 | return duration(timing.value().get().first_upstream_tx_byte_sent_, stream_info_); |
153 | 54 | } |
154 | | |
155 | 54 | absl::optional<std::chrono::nanoseconds> TimingUtility::lastUpstreamTxByteSent() { |
156 | 54 | OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_); |
157 | 54 | if (!timing) { |
158 | 54 | return absl::nullopt; |
159 | 54 | } |
160 | 0 | return duration(timing.value().get().last_upstream_tx_byte_sent_, stream_info_); |
161 | 54 | } |
162 | | |
163 | 54 | absl::optional<std::chrono::nanoseconds> TimingUtility::firstUpstreamRxByteReceived() { |
164 | 54 | OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_); |
165 | 54 | if (!timing) { |
166 | 54 | return absl::nullopt; |
167 | 54 | } |
168 | 0 | return duration(timing.value().get().first_upstream_rx_byte_received_, stream_info_); |
169 | 54 | } |
170 | | |
171 | 54 | absl::optional<std::chrono::nanoseconds> TimingUtility::lastUpstreamRxByteReceived() { |
172 | 54 | OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_); |
173 | 54 | if (!timing) { |
174 | 54 | return absl::nullopt; |
175 | 54 | } |
176 | 0 | return duration(timing.value().get().last_upstream_rx_byte_received_, stream_info_); |
177 | 54 | } |
178 | | |
179 | 0 | absl::optional<std::chrono::nanoseconds> TimingUtility::upstreamHandshakeComplete() { |
180 | 0 | OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_); |
181 | 0 | if (!timing) { |
182 | 0 | return absl::nullopt; |
183 | 0 | } |
184 | 0 | return duration(timing.value().get().upstreamHandshakeComplete(), stream_info_); |
185 | 0 | } |
186 | | |
187 | 54 | absl::optional<std::chrono::nanoseconds> TimingUtility::firstDownstreamTxByteSent() { |
188 | 54 | OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming(); |
189 | 54 | if (!timing) { |
190 | 0 | return absl::nullopt; |
191 | 0 | } |
192 | 54 | return duration(timing.value().get().firstDownstreamTxByteSent(), stream_info_); |
193 | 54 | } |
194 | | |
195 | 54 | absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamTxByteSent() { |
196 | 54 | OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming(); |
197 | 54 | if (!timing) { |
198 | 0 | return absl::nullopt; |
199 | 0 | } |
200 | 54 | return duration(timing.value().get().lastDownstreamTxByteSent(), stream_info_); |
201 | 54 | } |
202 | | |
203 | 108 | absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamRxByteReceived() { |
204 | 108 | OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming(); |
205 | 108 | if (!timing) { |
206 | 0 | return absl::nullopt; |
207 | 0 | } |
208 | 108 | return duration(timing.value().get().lastDownstreamRxByteReceived(), stream_info_); |
209 | 108 | } |
210 | | |
211 | 0 | absl::optional<std::chrono::nanoseconds> TimingUtility::downstreamHandshakeComplete() { |
212 | 0 | OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming(); |
213 | 0 | if (!timing) { |
214 | 0 | return absl::nullopt; |
215 | 0 | } |
216 | 0 | return duration(timing.value().get().downstreamHandshakeComplete(), stream_info_); |
217 | 0 | } |
218 | | |
219 | 0 | absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamAckReceived() { |
220 | 0 | OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming(); |
221 | 0 | if (!timing) { |
222 | 0 | return absl::nullopt; |
223 | 0 | } |
224 | 0 | return duration(timing.value().get().lastDownstreamAckReceived(), stream_info_); |
225 | 0 | } |
226 | | |
227 | | const std::string& |
228 | 0 | Utility::formatDownstreamAddressNoPort(const Network::Address::Instance& address) { |
229 | 0 | if (address.type() == Network::Address::Type::Ip) { |
230 | 0 | return address.ip()->addressAsString(); |
231 | 0 | } else { |
232 | 0 | return address.asString(); |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | | const std::string |
237 | 0 | Utility::formatDownstreamAddressJustPort(const Network::Address::Instance& address) { |
238 | 0 | std::string port; |
239 | 0 | if (address.type() == Network::Address::Type::Ip) { |
240 | 0 | port = std::to_string(address.ip()->port()); |
241 | 0 | } |
242 | 0 | return port; |
243 | 0 | } |
244 | | |
245 | | absl::optional<uint32_t> |
246 | 0 | Utility::extractDownstreamAddressJustPort(const Network::Address::Instance& address) { |
247 | 0 | if (address.type() == Network::Address::Type::Ip) { |
248 | 0 | return address.ip()->port(); |
249 | 0 | } |
250 | 0 | return {}; |
251 | 0 | } |
252 | | |
253 | | const absl::optional<Http::Code> |
254 | 0 | ProxyStatusUtils::recommendedHttpStatusCode(const ProxyStatusError proxy_status) { |
255 | | // This switch statement was derived from the mapping from proxy error type to |
256 | | // recommended HTTP status code in |
257 | | // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-proxy-status-05#section-2.3 and below. |
258 | | // |
259 | | // TODO(ambuc): Replace this with the non-draft URL when finalized. |
260 | 0 | switch (proxy_status) { |
261 | 0 | case ProxyStatusError::DnsTimeout: |
262 | 0 | case ProxyStatusError::ConnectionTimeout: |
263 | 0 | case ProxyStatusError::ConnectionReadTimeout: |
264 | 0 | case ProxyStatusError::ConnectionWriteTimeout: |
265 | 0 | case ProxyStatusError::HttpResponseTimeout: |
266 | 0 | return Http::Code::GatewayTimeout; // 504 |
267 | 0 | case ProxyStatusError::DnsError: |
268 | 0 | case ProxyStatusError::DestinationIpProhibited: |
269 | 0 | case ProxyStatusError::DestinationIpUnroutable: |
270 | 0 | case ProxyStatusError::ConnectionRefused: |
271 | 0 | case ProxyStatusError::ConnectionTerminated: |
272 | 0 | case ProxyStatusError::TlsProtocolError: |
273 | 0 | case ProxyStatusError::TlsCertificateError: |
274 | 0 | case ProxyStatusError::TlsAlertReceived: |
275 | 0 | case ProxyStatusError::HttpResponseIncomplete: |
276 | 0 | case ProxyStatusError::HttpResponseHeaderSectionSize: |
277 | 0 | case ProxyStatusError::HttpResponseHeaderSize: |
278 | 0 | case ProxyStatusError::HttpResponseBodySize: |
279 | 0 | case ProxyStatusError::HttpResponseTrailerSectionSize: |
280 | 0 | case ProxyStatusError::HttpResponseTrailerSize: |
281 | 0 | case ProxyStatusError::HttpResponseTransferCoding: |
282 | 0 | case ProxyStatusError::HttpResponseContentCoding: |
283 | 0 | case ProxyStatusError::HttpUpgradeFailed: |
284 | 0 | case ProxyStatusError::HttpProtocolError: |
285 | 0 | case ProxyStatusError::ProxyLoopDetected: |
286 | 0 | return Http::Code::BadGateway; // 502 |
287 | 0 | case ProxyStatusError::DestinationNotFound: |
288 | 0 | case ProxyStatusError::ProxyInternalError: |
289 | 0 | case ProxyStatusError::ProxyConfigurationError: |
290 | 0 | return Http::Code::InternalServerError; // 500 |
291 | 0 | case ProxyStatusError::DestinationUnavailable: |
292 | 0 | case ProxyStatusError::ConnectionLimitReached: |
293 | 0 | return Http::Code::ServiceUnavailable; // 503 |
294 | 0 | case ProxyStatusError::HttpRequestDenied: |
295 | 0 | return Http::Code::Forbidden; // 403 |
296 | 0 | case ProxyStatusError::ProxyInternalResponse: |
297 | 0 | case ProxyStatusError::HttpRequestError: |
298 | 0 | default: |
299 | 0 | return absl::nullopt; |
300 | 0 | } |
301 | 0 | } |
302 | | |
303 | | const std::string ProxyStatusUtils::makeProxyName( |
304 | | absl::string_view node_id, absl::string_view server_name, |
305 | | const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager:: |
306 | 5.61k | ProxyStatusConfig* proxy_status_config) { |
307 | 5.61k | if (proxy_status_config == nullptr) { |
308 | 5.14k | return std::string(server_name); |
309 | 5.14k | } |
310 | | // For the proxy name, the config specified either a preset proxy name or a literal proxy name. |
311 | 461 | switch (proxy_status_config->proxy_name_case()) { |
312 | 48 | case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager:: |
313 | 48 | ProxyStatusConfig::ProxyNameCase::kLiteralProxyName: { |
314 | 48 | return std::string(proxy_status_config->literal_proxy_name()); |
315 | 0 | } |
316 | 161 | case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager:: |
317 | 161 | ProxyStatusConfig::ProxyNameCase::kUseNodeId: { |
318 | 161 | return std::string(node_id); |
319 | 0 | } |
320 | 252 | case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager:: |
321 | 252 | ProxyStatusConfig::ProxyNameCase::PROXY_NAME_NOT_SET: |
322 | 252 | default: { |
323 | 252 | return std::string(server_name); |
324 | 252 | } |
325 | 461 | } |
326 | 461 | } |
327 | | |
328 | | const std::string ProxyStatusUtils::makeProxyStatusHeader( |
329 | | const StreamInfo& stream_info, const ProxyStatusError error, absl::string_view proxy_name, |
330 | | const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager:: |
331 | 0 | ProxyStatusConfig& proxy_status_config) { |
332 | 0 | std::vector<std::string> retval = {}; |
333 | |
|
334 | 0 | retval.push_back(std::string(proxy_name)); |
335 | |
|
336 | 0 | retval.push_back(absl::StrFormat("error=%s", proxyStatusErrorToString(error))); |
337 | |
|
338 | 0 | if (!proxy_status_config.remove_details() && stream_info.responseCodeDetails().has_value()) { |
339 | 0 | std::vector<std::string> details = {}; |
340 | 0 | details.push_back(stream_info.responseCodeDetails().value()); |
341 | 0 | if (!proxy_status_config.remove_connection_termination_details() && |
342 | 0 | stream_info.connectionTerminationDetails().has_value()) { |
343 | 0 | details.push_back(stream_info.connectionTerminationDetails().value()); |
344 | 0 | } |
345 | 0 | if (!proxy_status_config.remove_response_flags() && stream_info.hasAnyResponseFlag()) { |
346 | 0 | details.push_back(ResponseFlagUtils::toShortString(stream_info)); |
347 | 0 | } |
348 | 0 | retval.push_back( |
349 | 0 | absl::StrFormat("details=\"%s\"", StringUtil::escape(absl::StrJoin(details, "; ")))); |
350 | 0 | } |
351 | |
|
352 | 0 | return absl::StrJoin(retval, "; "); |
353 | 0 | } |
354 | | |
355 | | const absl::string_view |
356 | 0 | ProxyStatusUtils::proxyStatusErrorToString(const ProxyStatusError proxy_status) { |
357 | 0 | switch (proxy_status) { |
358 | 0 | case ProxyStatusError::DnsTimeout: |
359 | 0 | return DNS_TIMEOUT; |
360 | 0 | case ProxyStatusError::DnsError: |
361 | 0 | return DNS_ERROR; |
362 | 0 | case ProxyStatusError::DestinationNotFound: |
363 | 0 | return DESTINATION_NOT_FOUND; |
364 | 0 | case ProxyStatusError::DestinationUnavailable: |
365 | 0 | return DESTINATION_UNAVAILABLE; |
366 | 0 | case ProxyStatusError::DestinationIpProhibited: |
367 | 0 | return DESTINATION_IP_PROHIBITED; |
368 | 0 | case ProxyStatusError::DestinationIpUnroutable: |
369 | 0 | return DESTINATION_IP_UNROUTABLE; |
370 | 0 | case ProxyStatusError::ConnectionRefused: |
371 | 0 | return CONNECTION_REFUSED; |
372 | 0 | case ProxyStatusError::ConnectionTerminated: |
373 | 0 | return CONNECTION_TERMINATED; |
374 | 0 | case ProxyStatusError::ConnectionTimeout: |
375 | 0 | return CONNECTION_TIMEOUT; |
376 | 0 | case ProxyStatusError::ConnectionReadTimeout: |
377 | 0 | return CONNECTION_READ_TIMEOUT; |
378 | 0 | case ProxyStatusError::ConnectionWriteTimeout: |
379 | 0 | return CONNECTION_WRITE_TIMEOUT; |
380 | 0 | case ProxyStatusError::ConnectionLimitReached: |
381 | 0 | return CONNECTION_LIMIT_REACHED; |
382 | 0 | case ProxyStatusError::TlsProtocolError: |
383 | 0 | return TLS_PROTOCOL_ERROR; |
384 | 0 | case ProxyStatusError::TlsCertificateError: |
385 | 0 | return TLS_CERTIFICATE_ERROR; |
386 | 0 | case ProxyStatusError::TlsAlertReceived: |
387 | 0 | return TLS_ALERT_RECEIVED; |
388 | 0 | case ProxyStatusError::HttpRequestError: |
389 | 0 | return HTTP_REQUEST_ERROR; |
390 | 0 | case ProxyStatusError::HttpRequestDenied: |
391 | 0 | return HTTP_REQUEST_DENIED; |
392 | 0 | case ProxyStatusError::HttpResponseIncomplete: |
393 | 0 | return HTTP_RESPONSE_INCOMPLETE; |
394 | 0 | case ProxyStatusError::HttpResponseHeaderSectionSize: |
395 | 0 | return HTTP_RESPONSE_HEADER_SECTION_SIZE; |
396 | 0 | case ProxyStatusError::HttpResponseHeaderSize: |
397 | 0 | return HTTP_RESPONSE_HEADER_SIZE; |
398 | 0 | case ProxyStatusError::HttpResponseBodySize: |
399 | 0 | return HTTP_RESPONSE_BODY_SIZE; |
400 | 0 | case ProxyStatusError::HttpResponseTrailerSectionSize: |
401 | 0 | return HTTP_RESPONSE_TRAILER_SECTION_SIZE; |
402 | 0 | case ProxyStatusError::HttpResponseTrailerSize: |
403 | 0 | return HTTP_RESPONSE_TRAILER_SIZE; |
404 | 0 | case ProxyStatusError::HttpResponseTransferCoding: |
405 | 0 | return HTTP_RESPONSE_TRANSFER_CODING; |
406 | 0 | case ProxyStatusError::HttpResponseContentCoding: |
407 | 0 | return HTTP_RESPONSE_CONTENT_CODING; |
408 | 0 | case ProxyStatusError::HttpResponseTimeout: |
409 | 0 | return HTTP_RESPONSE_TIMEOUT; |
410 | 0 | case ProxyStatusError::HttpUpgradeFailed: |
411 | 0 | return HTTP_UPGRADE_FAILED; |
412 | 0 | case ProxyStatusError::HttpProtocolError: |
413 | 0 | return HTTP_PROTOCOL_ERROR; |
414 | 0 | case ProxyStatusError::ProxyInternalResponse: |
415 | 0 | return PROXY_INTERNAL_RESPONSE; |
416 | 0 | case ProxyStatusError::ProxyInternalError: |
417 | 0 | return PROXY_INTERNAL_ERROR; |
418 | 0 | case ProxyStatusError::ProxyConfigurationError: |
419 | 0 | return PROXY_CONFIGURATION_ERROR; |
420 | 0 | case ProxyStatusError::ProxyLoopDetected: |
421 | 0 | return PROXY_LOOP_DETECTED; |
422 | 0 | default: |
423 | 0 | return "-"; |
424 | 0 | } |
425 | 0 | } |
426 | | |
427 | | const absl::optional<ProxyStatusError> |
428 | 152 | ProxyStatusUtils::fromStreamInfo(const StreamInfo& stream_info) { |
429 | | // NB: This mapping from Envoy-specific CoreResponseFlag enum to Proxy-Status |
430 | | // error enum is lossy, since CoreResponseFlag is really a bitset of many |
431 | | // CoreResponseFlag enums. |
432 | 152 | if (stream_info.hasResponseFlag(CoreResponseFlag::FailedLocalHealthCheck)) { |
433 | 0 | return ProxyStatusError::DestinationUnavailable; |
434 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::NoHealthyUpstream)) { |
435 | 0 | return ProxyStatusError::DestinationUnavailable; |
436 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRequestTimeout)) { |
437 | 0 | return ProxyStatusError::HttpResponseTimeout; |
438 | 0 | } |
439 | | |
440 | 152 | if (Runtime::runtimeFeatureEnabled( |
441 | 152 | "envoy.reloadable_features.proxy_status_mapping_more_core_response_flags")) { |
442 | 152 | if (stream_info.hasResponseFlag(CoreResponseFlag::DurationTimeout)) { |
443 | 0 | return ProxyStatusError::ConnectionTimeout; |
444 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::LocalReset)) { |
445 | 0 | return ProxyStatusError::ConnectionTimeout; |
446 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRemoteReset)) { |
447 | 0 | return ProxyStatusError::ConnectionTerminated; |
448 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionFailure)) { |
449 | 0 | return ProxyStatusError::ConnectionRefused; |
450 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::UnauthorizedExternalService)) { |
451 | 0 | return ProxyStatusError::ConnectionRefused; |
452 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionTermination)) { |
453 | 0 | return ProxyStatusError::ConnectionTerminated; |
454 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::OverloadManager)) { |
455 | 0 | return ProxyStatusError::ConnectionLimitReached; |
456 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::DropOverLoad)) { |
457 | 0 | return ProxyStatusError::ConnectionLimitReached; |
458 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::FaultInjected)) { |
459 | 0 | return ProxyStatusError::HttpRequestError; |
460 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::DownstreamConnectionTermination)) { |
461 | 0 | return ProxyStatusError::ConnectionTerminated; |
462 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::DownstreamRemoteReset)) { |
463 | 0 | return ProxyStatusError::ConnectionTerminated; |
464 | 0 | } |
465 | 152 | } else { |
466 | 0 | if (stream_info.hasResponseFlag(CoreResponseFlag::LocalReset)) { |
467 | 0 | return ProxyStatusError::ConnectionTimeout; |
468 | 0 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRemoteReset)) { |
469 | 0 | return ProxyStatusError::ConnectionTerminated; |
470 | 0 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionFailure)) { |
471 | 0 | return ProxyStatusError::ConnectionRefused; |
472 | 0 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionTermination)) { |
473 | 0 | return ProxyStatusError::ConnectionTerminated; |
474 | 0 | } |
475 | 0 | } |
476 | | |
477 | 152 | if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamOverflow)) { |
478 | 0 | return ProxyStatusError::ConnectionLimitReached; |
479 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::NoRouteFound)) { |
480 | 0 | return ProxyStatusError::DestinationNotFound; |
481 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::RateLimited)) { |
482 | 0 | return ProxyStatusError::ConnectionLimitReached; |
483 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::RateLimitServiceError)) { |
484 | 0 | return ProxyStatusError::ConnectionLimitReached; |
485 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRetryLimitExceeded)) { |
486 | 0 | return ProxyStatusError::DestinationUnavailable; |
487 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::StreamIdleTimeout)) { |
488 | 0 | return ProxyStatusError::HttpResponseTimeout; |
489 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::InvalidEnvoyRequestHeaders)) { |
490 | 0 | return ProxyStatusError::HttpRequestError; |
491 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::DownstreamProtocolError)) { |
492 | 0 | return ProxyStatusError::HttpRequestError; |
493 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamMaxStreamDurationReached)) { |
494 | 0 | return ProxyStatusError::HttpResponseTimeout; |
495 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::NoFilterConfigFound)) { |
496 | 0 | return ProxyStatusError::ProxyConfigurationError; |
497 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamProtocolError)) { |
498 | 0 | return ProxyStatusError::HttpProtocolError; |
499 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::NoClusterFound)) { |
500 | 0 | return ProxyStatusError::DestinationUnavailable; |
501 | 152 | } else if (stream_info.hasResponseFlag(CoreResponseFlag::DnsResolutionFailed)) { |
502 | 0 | return ProxyStatusError::DnsError; |
503 | 152 | } else { |
504 | 152 | return absl::nullopt; |
505 | 152 | } |
506 | 152 | } |
507 | | |
508 | | } // namespace StreamInfo |
509 | | } // namespace Envoy |