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/network/cidr_range.h"
9
#include "source/common/runtime/runtime_features.h"
10

            
11
#include "absl/status/statusor.h"
12
#include "absl/strings/str_format.h"
13

            
14
namespace Envoy {
15
namespace StreamInfo {
16

            
17
namespace {
18

            
19
// This flag is used to ensure that the responseFlagsVec() contains all the flags and no
20
// any new custom flags are registered after the responseFlagsVec() is initialized.
21
// NOTE: we expect all registrations of custom flags to happen during static initialization
22
// before the first use of responseFlagsVec(). So no thread safety is needed here.
23
425
bool& responseFlagsVecInitialized() { MUTABLE_CONSTRUCT_ON_FIRST_USE(bool, false); }
24

            
25
} // namespace
26

            
27
38
const std::string ResponseFlagUtils::toString(const StreamInfo& stream_info) {
28
38
  return toString(stream_info, true);
29
38
}
30

            
31
75499
const std::string ResponseFlagUtils::toShortString(const StreamInfo& stream_info) {
32
75499
  return toString(stream_info, false);
33
75499
}
34

            
35
75537
const std::string ResponseFlagUtils::toString(const StreamInfo& stream_info, bool use_long_name) {
36
  // We don't expect more than 4 flags are set. Relax to 16 since the vector is allocated on stack
37
  // anyway.
38
75537
  absl::InlinedVector<absl::string_view, 16> flag_strings_vec;
39

            
40
75537
  const auto& all_flag_strings = responseFlagsVec();
41
75561
  for (const auto flag : stream_info.responseFlags()) {
42
50604
    ASSERT(flag.value() < all_flag_strings.size(), "Flag value out of range");
43

            
44
50604
    const auto flag_strings = all_flag_strings[flag.value()];
45
50604
    flag_strings_vec.push_back(use_long_name ? flag_strings.long_string_
46
50604
                                             : flag_strings.short_string_);
47
50604
  }
48
75537
  if (flag_strings_vec.empty()) {
49
24993
    return std::string(NONE);
50
24993
  }
51
50544
  return absl::StrJoin(flag_strings_vec, ",");
52
75537
}
53

            
54
978
ResponseFlagUtils::ResponseFlagsMapType& ResponseFlagUtils::mutableResponseFlagsMap() {
55
978
  MUTABLE_CONSTRUCT_ON_FIRST_USE(ResponseFlagsMapType, []() {
56
978
    ResponseFlagsMapType map;
57
    // Initialize the map with the all core flags first to ensure no custom flags
58
    // conflict with them.
59
978
    RELEASE_ASSERT(CORE_RESPONSE_FLAGS.size() == CoreResponseFlag::LastFlag + 1,
60
978
                   "Not all inlined flags are contained by CORE_RESPONSE_FLAGS.");
61

            
62
978
    map.reserve(CORE_RESPONSE_FLAGS.size());
63
978
    for (const auto& flag : CORE_RESPONSE_FLAGS) {
64
978
      map.emplace(flag.short_string_, FlagLongString{flag.flag_, std::string(flag.long_string_)});
65
978
    }
66
978
    RELEASE_ASSERT(map.size() == CORE_RESPONSE_FLAGS.size(),
67
978
                   "Duplicate flags in CORE_RESPONSE_FLAGS");
68
978
    return map;
69
978
  }());
70
978
}
71

            
72
ResponseFlag ResponseFlagUtils::registerCustomFlag(absl::string_view custom_flag,
73
4
                                                   absl::string_view custom_flag_long) {
74
4
  auto& mutable_flags = mutableResponseFlagsMap();
75

            
76
4
  RELEASE_ASSERT(!responseFlagsVecInitialized(),
77
4
                 "Cannot register custom flags after initialization");
78

            
79
4
  RELEASE_ASSERT(!mutable_flags.contains(custom_flag),
80
4
                 fmt::format("Flag: {}/{} already registered", custom_flag, custom_flag_long));
81

            
82
4
  const uint16_t next_flag = mutable_flags.size();
83

            
84
4
  mutable_flags.emplace(custom_flag, FlagLongString{next_flag, std::string(custom_flag_long)});
85

            
86
4
  return next_flag;
87
4
}
88

            
89
75744
const ResponseFlagUtils::ResponseFlagsVecType& ResponseFlagUtils::responseFlagsVec() {
90
75744
  CONSTRUCT_ON_FIRST_USE(ResponseFlagsVecType, []() {
91
75744
    static_assert(CoreResponseFlag::LastFlag == 29,
92
75744
                  "A flag has been added. Add the new flag to CORE_RESPONSE_FLAGS.");
93

            
94
75744
    responseFlagsVecInitialized() = true;
95

            
96
75744
    ResponseFlagsVecType res;
97

            
98
75744
    uint16_t max_flag = CoreResponseFlag::LastFlag;
99
75744
    for (const auto& flag : responseFlagsMap()) {
100
75744
      if (flag.second.flag_.value() > max_flag) {
101
75744
        max_flag = flag.second.flag_.value();
102
75744
      }
103
75744
    }
104

            
105
75744
    res.resize(max_flag + 1);
106

            
107
75744
    for (const auto& flag : responseFlagsMap()) {
108
75744
      res[flag.second.flag_.value()] = {absl::string_view(flag.first),
109
75744
                                        absl::string_view(flag.second.long_string_),
110
75744
                                        flag.second.flag_};
111
75744
    }
112

            
113
75744
    return res;
114
75744
  }());
115
75744
}
116

            
117
974
const ResponseFlagUtils::ResponseFlagsMapType& ResponseFlagUtils::responseFlagsMap() {
118
974
  return mutableResponseFlagsMap();
119
974
}
120

            
121
64
absl::optional<ResponseFlag> ResponseFlagUtils::toResponseFlag(absl::string_view flag) {
122
64
  const auto iter = responseFlagsMap().find(flag);
123
64
  if (iter != responseFlagsMap().end()) {
124
63
    return iter->second.flag_;
125
63
  }
126
1
  return absl::nullopt;
127
64
}
128

            
129
CustomResponseFlag::CustomResponseFlag(absl::string_view flag, absl::string_view flag_long)
130
4
    : flag_(ResponseFlagUtils::registerCustomFlag(flag, flag_long)) {}
131

            
132
450
OptRef<const UpstreamTiming> getUpstreamTiming(const StreamInfo& stream_info) {
133
450
  OptRef<const UpstreamInfo> info = stream_info.upstreamInfo();
134
450
  if (!info.has_value()) {
135
116
    return {};
136
116
  }
137
334
  return info.value().get().upstreamTiming();
138
450
}
139

            
140
absl::optional<std::chrono::nanoseconds> duration(const absl::optional<MonotonicTime>& time,
141
586
                                                  const StreamInfo& stream_info) {
142
586
  if (!time.has_value()) {
143
293
    return absl::nullopt;
144
293
  }
145
293
  return std::chrono::duration_cast<std::chrono::nanoseconds>(time.value() -
146
293
                                                              stream_info.startTimeMonotonic());
147
586
}
148

            
149
87
absl::optional<std::chrono::nanoseconds> TimingUtility::firstUpstreamTxByteSent() {
150
87
  OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_);
151
87
  if (!timing) {
152
22
    return absl::nullopt;
153
22
  }
154
65
  return duration(timing.value().get().first_upstream_tx_byte_sent_, stream_info_);
155
87
}
156

            
157
143
absl::optional<std::chrono::nanoseconds> TimingUtility::lastUpstreamTxByteSent() {
158
143
  OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_);
159
143
  if (!timing) {
160
49
    return absl::nullopt;
161
49
  }
162
94
  return duration(timing.value().get().last_upstream_tx_byte_sent_, stream_info_);
163
143
}
164

            
165
128
absl::optional<std::chrono::nanoseconds> TimingUtility::firstUpstreamRxByteReceived() {
166
128
  OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_);
167
128
  if (!timing) {
168
23
    return absl::nullopt;
169
23
  }
170
105
  return duration(timing.value().get().first_upstream_rx_byte_received_, stream_info_);
171
128
}
172

            
173
88
absl::optional<std::chrono::nanoseconds> TimingUtility::lastUpstreamRxByteReceived() {
174
88
  OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_);
175
88
  if (!timing) {
176
22
    return absl::nullopt;
177
22
  }
178
66
  return duration(timing.value().get().last_upstream_rx_byte_received_, stream_info_);
179
88
}
180

            
181
2
absl::optional<std::chrono::nanoseconds> TimingUtility::firstUpstreamRxBodyByteReceived() {
182
2
  OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_);
183
2
  if (!timing) {
184
    return absl::nullopt;
185
  }
186
2
  return duration(timing.value().get().first_upstream_rx_body_byte_received_, stream_info_);
187
2
}
188

            
189
2
absl::optional<std::chrono::nanoseconds> TimingUtility::upstreamHandshakeComplete() {
190
2
  OptRef<const UpstreamTiming> timing = getUpstreamTiming(stream_info_);
191
2
  if (!timing) {
192
    return absl::nullopt;
193
  }
194
2
  return duration(timing.value().get().upstreamHandshakeComplete(), stream_info_);
195
2
}
196

            
197
81
absl::optional<std::chrono::nanoseconds> TimingUtility::firstDownstreamTxByteSent() {
198
81
  OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming();
199
81
  if (!timing) {
200
23
    return absl::nullopt;
201
23
  }
202
58
  return duration(timing.value().get().firstDownstreamTxByteSent(), stream_info_);
203
81
}
204

            
205
100
absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamTxByteSent() {
206
100
  OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming();
207
100
  if (!timing) {
208
23
    return absl::nullopt;
209
23
  }
210
77
  return duration(timing.value().get().lastDownstreamTxByteSent(), stream_info_);
211
100
}
212

            
213
2
absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamHeaderRxByteReceived() {
214
2
  OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming();
215
2
  if (!timing) {
216
    return absl::nullopt;
217
  }
218
2
  return duration(timing.value().get().lastDownstreamHeaderRxByteReceived(), stream_info_);
219
2
}
220

            
221
111
absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamRxByteReceived() {
222
111
  OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming();
223
111
  if (!timing) {
224
26
    return absl::nullopt;
225
26
  }
226
85
  return duration(timing.value().get().lastDownstreamRxByteReceived(), stream_info_);
227
111
}
228

            
229
6
absl::optional<std::chrono::nanoseconds> TimingUtility::downstreamHandshakeComplete() {
230
6
  OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming();
231
6
  if (!timing) {
232
    return absl::nullopt;
233
  }
234
6
  return duration(timing.value().get().downstreamHandshakeComplete(), stream_info_);
235
6
}
236

            
237
25
absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamAckReceived() {
238
25
  OptRef<const DownstreamTiming> timing = stream_info_.downstreamTiming();
239
25
  if (!timing) {
240
1
    return absl::nullopt;
241
1
  }
242
24
  return duration(timing.value().get().lastDownstreamAckReceived(), stream_info_);
243
25
}
244

            
245
const std::string Utility::formatDownstreamAddressNoPort(const Network::Address::Instance& address,
246
120
                                                         absl::optional<int> mask_prefix_len) {
247
  // No masking - return address without port
248
120
  if (!mask_prefix_len.has_value()) {
249
97
    if (address.type() == Network::Address::Type::Ip) {
250
96
      return address.ip()->addressAsString();
251
96
    } else {
252
1
      return address.asString();
253
1
    }
254
97
  }
255

            
256
23
  std::string masked_address;
257
23
  if (address.type() != Network::Address::Type::Ip) {
258
    return masked_address;
259
  }
260

            
261
23
  int length = mask_prefix_len.value_or(
262
23
      address.ip()->version() == Network::Address::IpVersion::v4 ? 32 : 128);
263

            
264
  // CidrRange::create() requires a shared_ptr. We create one with a no-op deleter since we don't
265
  // own the address and shouldn't delete it.
266
23
  Network::Address::InstanceConstSharedPtr address_ptr(&address,
267
23
                                                       [](const Network::Address::Instance*) {});
268

            
269
23
  auto cidr_range_or_error =
270
23
      Network::Address::CidrRange::create(address_ptr, length, absl::nullopt);
271

            
272
23
  if (cidr_range_or_error.ok()) {
273
23
    masked_address = cidr_range_or_error.value().asString();
274
23
  }
275
23
  return masked_address;
276
23
}
277

            
278
const std::string
279
25
Utility::formatDownstreamAddressJustPort(const Network::Address::Instance& address) {
280
25
  std::string port;
281
25
  if (address.type() == Network::Address::Type::Ip) {
282
23
    port = std::to_string(address.ip()->port());
283
23
  }
284
25
  return port;
285
25
}
286

            
287
absl::optional<uint32_t>
288
15
Utility::extractDownstreamAddressJustPort(const Network::Address::Instance& address) {
289
15
  if (address.type() == Network::Address::Type::Ip) {
290
13
    return address.ip()->port();
291
13
  }
292
2
  return {};
293
15
}
294

            
295
const std::string
296
17
Utility::formatDownstreamAddressJustEndpointId(const Network::Address::Instance& address) {
297
17
  std::string endpoint_id;
298
17
  if (address.type() == Network::Address::Type::EnvoyInternal) {
299
11
    endpoint_id = address.envoyInternalAddress()->endpointId();
300
11
  }
301
17
  return endpoint_id;
302
17
}
303

            
304
const absl::optional<Http::Code>
305
36
ProxyStatusUtils::recommendedHttpStatusCode(const ProxyStatusError proxy_status) {
306
  // This switch statement was derived from the mapping from proxy error type to
307
  // recommended HTTP status code in
308
  // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-proxy-status-05#section-2.3 and below.
309
  //
310
  // TODO(ambuc): Replace this with the non-draft URL when finalized.
311
36
  switch (proxy_status) {
312
3
  case ProxyStatusError::DnsTimeout:
313
4
  case ProxyStatusError::ConnectionTimeout:
314
5
  case ProxyStatusError::ConnectionReadTimeout:
315
6
  case ProxyStatusError::ConnectionWriteTimeout:
316
8
  case ProxyStatusError::HttpResponseTimeout:
317
8
    return Http::Code::GatewayTimeout; // 504
318
1
  case ProxyStatusError::DnsError:
319
2
  case ProxyStatusError::DestinationIpProhibited:
320
3
  case ProxyStatusError::DestinationIpUnroutable:
321
4
  case ProxyStatusError::ConnectionRefused:
322
5
  case ProxyStatusError::ConnectionTerminated:
323
6
  case ProxyStatusError::TlsProtocolError:
324
7
  case ProxyStatusError::TlsCertificateError:
325
8
  case ProxyStatusError::TlsAlertReceived:
326
9
  case ProxyStatusError::HttpResponseIncomplete:
327
10
  case ProxyStatusError::HttpResponseHeaderSectionSize:
328
11
  case ProxyStatusError::HttpResponseHeaderSize:
329
12
  case ProxyStatusError::HttpResponseBodySize:
330
13
  case ProxyStatusError::HttpResponseTrailerSectionSize:
331
14
  case ProxyStatusError::HttpResponseTrailerSize:
332
15
  case ProxyStatusError::HttpResponseTransferCoding:
333
16
  case ProxyStatusError::HttpResponseContentCoding:
334
17
  case ProxyStatusError::HttpUpgradeFailed:
335
18
  case ProxyStatusError::HttpProtocolError:
336
19
  case ProxyStatusError::ProxyLoopDetected:
337
19
    return Http::Code::BadGateway; // 502
338
1
  case ProxyStatusError::DestinationNotFound:
339
2
  case ProxyStatusError::ProxyInternalError:
340
3
  case ProxyStatusError::ProxyConfigurationError:
341
3
    return Http::Code::InternalServerError; // 500
342
2
  case ProxyStatusError::DestinationUnavailable:
343
3
  case ProxyStatusError::ConnectionLimitReached:
344
3
    return Http::Code::ServiceUnavailable; // 503
345
1
  case ProxyStatusError::HttpRequestDenied:
346
1
    return Http::Code::Forbidden; // 403
347
1
  case ProxyStatusError::ProxyInternalResponse:
348
2
  case ProxyStatusError::HttpRequestError:
349
2
  default:
350
2
    return absl::nullopt;
351
36
  }
352
36
}
353

            
354
const std::string ProxyStatusUtils::makeProxyName(
355
    absl::string_view node_id, absl::string_view server_name,
356
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
357
22435
        ProxyStatusConfig* proxy_status_config) {
358
22435
  if (proxy_status_config == nullptr) {
359
22219
    return std::string(server_name);
360
22219
  }
361
  // For the proxy name, the config specified either a preset proxy name or a literal proxy name.
362
216
  switch (proxy_status_config->proxy_name_case()) {
363
1
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
364
1
      ProxyStatusConfig::ProxyNameCase::kLiteralProxyName: {
365
1
    return std::string(proxy_status_config->literal_proxy_name());
366
  }
367
2
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
368
2
      ProxyStatusConfig::ProxyNameCase::kUseNodeId: {
369
2
    return std::string(node_id);
370
  }
371
213
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
372
213
      ProxyStatusConfig::ProxyNameCase::PROXY_NAME_NOT_SET:
373
213
  default: {
374
213
    return std::string(server_name);
375
213
  }
376
216
  }
377
216
}
378

            
379
const std::string ProxyStatusUtils::makeProxyStatusHeader(
380
    const StreamInfo& stream_info, const ProxyStatusError error, absl::string_view proxy_name,
381
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
382
2136
        ProxyStatusConfig& proxy_status_config) {
383
2136
  std::vector<std::string> retval = {};
384

            
385
2136
  retval.push_back(std::string(proxy_name));
386

            
387
2136
  retval.push_back(absl::StrFormat("error=%s", proxyStatusErrorToString(error)));
388

            
389
2136
  if (!proxy_status_config.remove_details() && stream_info.responseCodeDetails().has_value()) {
390
2133
    std::vector<std::string> details = {};
391
2133
    details.push_back(stream_info.responseCodeDetails().value());
392
2133
    if (!proxy_status_config.remove_connection_termination_details() &&
393
2133
        stream_info.connectionTerminationDetails().has_value()) {
394
4
      details.push_back(stream_info.connectionTerminationDetails().value());
395
4
    }
396
2133
    if (!proxy_status_config.remove_response_flags() && stream_info.hasAnyResponseFlag()) {
397
2131
      details.push_back(ResponseFlagUtils::toShortString(stream_info));
398
2131
    }
399
2133
    retval.push_back(
400
2133
        absl::StrFormat("details=\"%s\"", StringUtil::escape(absl::StrJoin(details, "; "))));
401
2133
  }
402

            
403
2136
  return absl::StrJoin(retval, "; ");
404
2136
}
405

            
406
const absl::string_view
407
2168
ProxyStatusUtils::proxyStatusErrorToString(const ProxyStatusError proxy_status) {
408
2168
  switch (proxy_status) {
409
1
  case ProxyStatusError::DnsTimeout:
410
1
    return DNS_TIMEOUT;
411
1
  case ProxyStatusError::DnsError:
412
1
    return DNS_ERROR;
413
2061
  case ProxyStatusError::DestinationNotFound:
414
2061
    return DESTINATION_NOT_FOUND;
415
17
  case ProxyStatusError::DestinationUnavailable:
416
17
    return DESTINATION_UNAVAILABLE;
417
1
  case ProxyStatusError::DestinationIpProhibited:
418
1
    return DESTINATION_IP_PROHIBITED;
419
1
  case ProxyStatusError::DestinationIpUnroutable:
420
1
    return DESTINATION_IP_UNROUTABLE;
421
3
  case ProxyStatusError::ConnectionRefused:
422
3
    return CONNECTION_REFUSED;
423
28
  case ProxyStatusError::ConnectionTerminated:
424
28
    return CONNECTION_TERMINATED;
425
1
  case ProxyStatusError::ConnectionTimeout:
426
1
    return CONNECTION_TIMEOUT;
427
1
  case ProxyStatusError::ConnectionReadTimeout:
428
1
    return CONNECTION_READ_TIMEOUT;
429
1
  case ProxyStatusError::ConnectionWriteTimeout:
430
1
    return CONNECTION_WRITE_TIMEOUT;
431
1
  case ProxyStatusError::ConnectionLimitReached:
432
1
    return CONNECTION_LIMIT_REACHED;
433
1
  case ProxyStatusError::TlsProtocolError:
434
1
    return TLS_PROTOCOL_ERROR;
435
1
  case ProxyStatusError::TlsCertificateError:
436
1
    return TLS_CERTIFICATE_ERROR;
437
1
  case ProxyStatusError::TlsAlertReceived:
438
1
    return TLS_ALERT_RECEIVED;
439
1
  case ProxyStatusError::HttpRequestError:
440
1
    return HTTP_REQUEST_ERROR;
441
1
  case ProxyStatusError::HttpRequestDenied:
442
1
    return HTTP_REQUEST_DENIED;
443
1
  case ProxyStatusError::HttpResponseIncomplete:
444
1
    return HTTP_RESPONSE_INCOMPLETE;
445
1
  case ProxyStatusError::HttpResponseHeaderSectionSize:
446
1
    return HTTP_RESPONSE_HEADER_SECTION_SIZE;
447
1
  case ProxyStatusError::HttpResponseHeaderSize:
448
1
    return HTTP_RESPONSE_HEADER_SIZE;
449
1
  case ProxyStatusError::HttpResponseBodySize:
450
1
    return HTTP_RESPONSE_BODY_SIZE;
451
1
  case ProxyStatusError::HttpResponseTrailerSectionSize:
452
1
    return HTTP_RESPONSE_TRAILER_SECTION_SIZE;
453
1
  case ProxyStatusError::HttpResponseTrailerSize:
454
1
    return HTTP_RESPONSE_TRAILER_SIZE;
455
1
  case ProxyStatusError::HttpResponseTransferCoding:
456
1
    return HTTP_RESPONSE_TRANSFER_CODING;
457
1
  case ProxyStatusError::HttpResponseContentCoding:
458
1
    return HTTP_RESPONSE_CONTENT_CODING;
459
6
  case ProxyStatusError::HttpResponseTimeout:
460
6
    return HTTP_RESPONSE_TIMEOUT;
461
1
  case ProxyStatusError::HttpUpgradeFailed:
462
1
    return HTTP_UPGRADE_FAILED;
463
19
  case ProxyStatusError::HttpProtocolError:
464
19
    return HTTP_PROTOCOL_ERROR;
465
1
  case ProxyStatusError::ProxyInternalResponse:
466
1
    return PROXY_INTERNAL_RESPONSE;
467
1
  case ProxyStatusError::ProxyInternalError:
468
1
    return PROXY_INTERNAL_ERROR;
469
9
  case ProxyStatusError::ProxyConfigurationError:
470
9
    return PROXY_CONFIGURATION_ERROR;
471
1
  case ProxyStatusError::ProxyLoopDetected:
472
1
    return PROXY_LOOP_DETECTED;
473
  default:
474
    return "-";
475
2168
  }
476
2168
}
477

            
478
const absl::optional<ProxyStatusError>
479
2239
ProxyStatusUtils::fromStreamInfo(const StreamInfo& stream_info) {
480
  // NB: This mapping from Envoy-specific CoreResponseFlag enum to Proxy-Status
481
  // error enum is lossy, since CoreResponseFlag is really a bitset of many
482
  // CoreResponseFlag enums.
483
2239
  if (stream_info.hasResponseFlag(CoreResponseFlag::FailedLocalHealthCheck)) {
484
2
    return ProxyStatusError::DestinationUnavailable;
485
2237
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::NoHealthyUpstream)) {
486
1
    return ProxyStatusError::DestinationUnavailable;
487
2236
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRequestTimeout)) {
488
6
    return ProxyStatusError::HttpResponseTimeout;
489
6
  }
490

            
491
2230
  if (stream_info.hasResponseFlag(CoreResponseFlag::DurationTimeout)) {
492
1
    return ProxyStatusError::ConnectionTimeout;
493
2229
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::LocalReset)) {
494
1
    return ProxyStatusError::ConnectionTimeout;
495
2228
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRemoteReset)) {
496
3
    return ProxyStatusError::ConnectionTerminated;
497
2225
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionFailure)) {
498
2
    return ProxyStatusError::ConnectionRefused;
499
2224
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::UnauthorizedExternalService)) {
500
2
    return ProxyStatusError::ConnectionRefused;
501
2222
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionTermination)) {
502
26
    return ProxyStatusError::ConnectionTerminated;
503
2216
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::OverloadManager)) {
504
1
    return ProxyStatusError::ConnectionLimitReached;
505
2194
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::DropOverLoad)) {
506
1
    return ProxyStatusError::ConnectionLimitReached;
507
2193
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::FaultInjected)) {
508
1
    return ProxyStatusError::HttpRequestError;
509
2192
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::DownstreamConnectionTermination)) {
510
1
    return ProxyStatusError::ConnectionTerminated;
511
2191
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::DownstreamRemoteReset)) {
512
1
    return ProxyStatusError::ConnectionTerminated;
513
1
  }
514

            
515
2190
  if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamOverflow)) {
516
1
    return ProxyStatusError::ConnectionLimitReached;
517
2189
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::NoRouteFound)) {
518
2061
    return ProxyStatusError::DestinationNotFound;
519
2153
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::RateLimited)) {
520
1
    return ProxyStatusError::ConnectionLimitReached;
521
127
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::RateLimitServiceError)) {
522
1
    return ProxyStatusError::ConnectionLimitReached;
523
126
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRetryLimitExceeded)) {
524
1
    return ProxyStatusError::DestinationUnavailable;
525
125
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::StreamIdleTimeout)) {
526
1
    return ProxyStatusError::HttpResponseTimeout;
527
124
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::InvalidEnvoyRequestHeaders)) {
528
1
    return ProxyStatusError::HttpRequestError;
529
123
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::DownstreamProtocolError)) {
530
1
    return ProxyStatusError::HttpRequestError;
531
122
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamMaxStreamDurationReached)) {
532
1
    return ProxyStatusError::HttpResponseTimeout;
533
121
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::NoFilterConfigFound)) {
534
1
    return ProxyStatusError::ProxyConfigurationError;
535
120
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamProtocolError)) {
536
19
    return ProxyStatusError::HttpProtocolError;
537
101
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::NoClusterFound)) {
538
16
    return ProxyStatusError::DestinationUnavailable;
539
92
  } else if (stream_info.hasResponseFlag(CoreResponseFlag::DnsResolutionFailed)) {
540
1
    return ProxyStatusError::DnsError;
541
85
  } else {
542
84
    return absl::nullopt;
543
84
  }
544
2190
}
545

            
546
} // namespace StreamInfo
547
} // namespace Envoy