Coverage Report

Created: 2024-09-19 09:45

/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