1
#pragma once
2

            
3
#include <chrono>
4
#include <cstdint>
5

            
6
#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"
7
#include "envoy/http/codes.h"
8
#include "envoy/stream_info/stream_info.h"
9

            
10
#include "absl/container/node_hash_map.h"
11

            
12
namespace Envoy {
13
namespace StreamInfo {
14

            
15
class CustomResponseFlag {
16
public:
17
  CustomResponseFlag(absl::string_view flag, absl::string_view flag_long);
18
13
  ResponseFlag flag() const { return flag_; }
19

            
20
private:
21
  ResponseFlag flag_;
22
};
23

            
24
// Register a custom response flag by specifying the flag and the long name of the flag.
25
// This macro should only be used in source files to register a flag.
26
#define REGISTER_CUSTOM_RESPONSE_FLAG(flag_short_string, flag_long_string)                         \
27
  static CustomResponseFlag /* NOLINT(fuchsia-statically-constructed-objects) */                   \
28
      registered_##flag_short_string{#flag_short_string, #flag_long_string};
29

            
30
// Get the registered flag value. This macro should only be used when calling the
31
// 'setResponseFlag' method in the StreamInfo class.
32
// NOTE: Never use this macro to initialize another static variable.
33
// Basically, this macro should only be used in the same source file where the flag is
34
// registered.
35
// If you want to use one flag in multiple files, you can declare a static function in
36
// the header file and define it in the source file to return the flag value. Here is an
37
// example (NOTE: this function should obey the same rule as the CUSTOM_RESPONSE_FLAG
38
// macro and cannot be used to initialize another static variable):
39
//
40
// // header.h
41
// ResponseFlag getRegisteredFlag();
42
// // source.cc
43
// REGISTER_CUSTOM_RESPONSE_FLAG(CF, CustomFlag);
44
// ResponseFlag getRegisteredFlag() { return CUSTOM_RESPONSE_FLAG(CF); }
45
2
#define CUSTOM_RESPONSE_FLAG(flag_short_string) registered_##flag_short_string.flag()
46

            
47
/**
48
 * Util class for ResponseFlags.
49
 */
50
class ResponseFlagUtils {
51
public:
52
  static const std::string toString(const StreamInfo& stream_info);
53
  static const std::string toShortString(const StreamInfo& stream_info);
54
  static absl::optional<ResponseFlag> toResponseFlag(absl::string_view response_flag);
55

            
56
  struct FlagStrings {
57
    absl::string_view short_string_;
58
    absl::string_view long_string_; // PascalCase string
59
    ResponseFlag flag_;
60
  };
61

            
62
  struct FlagLongString {
63
    ResponseFlag flag_;
64
    std::string long_string_; // PascalCase string
65
  };
66

            
67
  using ResponseFlagsVecType = std::vector<FlagStrings>;
68
  // Node hash map is used to avoid the key/value pair pointer change of the string_view when the
69
  // map is resized. And the performance is not a concern here because the map is only used when
70
  // loading the config.
71
  using ResponseFlagsMapType = absl::node_hash_map<std::string, FlagLongString>;
72
  static const ResponseFlagsVecType& responseFlagsVec();
73
  static const ResponseFlagsMapType& responseFlagsMap();
74

            
75
  // When adding a new flag, it's required to update the access log docs and the string
76
  // mapping below - ``CORE_RESPONSE_FLAGS``.
77
  constexpr static absl::string_view NONE = "-";
78
  constexpr static absl::string_view DOWNSTREAM_CONNECTION_TERMINATION = "DC";
79
  constexpr static absl::string_view FAILED_LOCAL_HEALTH_CHECK = "LH";
80
  constexpr static absl::string_view NO_HEALTHY_UPSTREAM = "UH";
81
  constexpr static absl::string_view UPSTREAM_REQUEST_TIMEOUT = "UT";
82
  constexpr static absl::string_view LOCAL_RESET = "LR";
83
  constexpr static absl::string_view UPSTREAM_REMOTE_RESET = "UR";
84
  constexpr static absl::string_view UPSTREAM_CONNECTION_FAILURE = "UF";
85
  constexpr static absl::string_view UPSTREAM_CONNECTION_TERMINATION = "UC";
86
  constexpr static absl::string_view UPSTREAM_OVERFLOW = "UO";
87
  constexpr static absl::string_view UPSTREAM_RETRY_LIMIT_EXCEEDED = "URX";
88
  constexpr static absl::string_view NO_ROUTE_FOUND = "NR";
89
  constexpr static absl::string_view DELAY_INJECTED = "DI";
90
  constexpr static absl::string_view FAULT_INJECTED = "FI";
91
  constexpr static absl::string_view RATE_LIMITED = "RL";
92
  constexpr static absl::string_view UNAUTHORIZED_EXTERNAL_SERVICE = "UAEX";
93
  constexpr static absl::string_view RATELIMIT_SERVICE_ERROR = "RLSE";
94
  constexpr static absl::string_view STREAM_IDLE_TIMEOUT = "SI";
95
  constexpr static absl::string_view INVALID_ENVOY_REQUEST_HEADERS = "IH";
96
  constexpr static absl::string_view DOWNSTREAM_PROTOCOL_ERROR = "DPE";
97
  constexpr static absl::string_view UPSTREAM_MAX_STREAM_DURATION_REACHED = "UMSDR";
98
  constexpr static absl::string_view RESPONSE_FROM_CACHE_FILTER = "RFCF";
99
  constexpr static absl::string_view NO_FILTER_CONFIG_FOUND = "NFCF";
100
  constexpr static absl::string_view DURATION_TIMEOUT = "DT";
101
  constexpr static absl::string_view UPSTREAM_PROTOCOL_ERROR = "UPE";
102
  constexpr static absl::string_view NO_CLUSTER_FOUND = "NC";
103
  constexpr static absl::string_view OVERLOAD_MANAGER = "OM";
104
  constexpr static absl::string_view DNS_FAIL = "DF";
105
  constexpr static absl::string_view DROP_OVERLOAD = "DO";
106
  constexpr static absl::string_view DOWNSTREAM_REMOTE_RESET = "DR";
107
  constexpr static absl::string_view UNCONDITIONAL_DROP_OVERLOAD = "UDO";
108

            
109
  constexpr static absl::string_view DOWNSTREAM_CONNECTION_TERMINATION_LONG =
110
      "DownstreamConnectionTermination";
111
  constexpr static absl::string_view FAILED_LOCAL_HEALTH_CHECK_LONG = "FailedLocalHealthCheck";
112
  constexpr static absl::string_view NO_HEALTHY_UPSTREAM_LONG = "NoHealthyUpstream";
113
  constexpr static absl::string_view UPSTREAM_REQUEST_TIMEOUT_LONG = "UpstreamRequestTimeout";
114
  constexpr static absl::string_view LOCAL_RESET_LONG = "LocalReset";
115
  constexpr static absl::string_view UPSTREAM_REMOTE_RESET_LONG = "UpstreamRemoteReset";
116
  constexpr static absl::string_view UPSTREAM_CONNECTION_FAILURE_LONG = "UpstreamConnectionFailure";
117
  constexpr static absl::string_view UPSTREAM_CONNECTION_TERMINATION_LONG =
118
      "UpstreamConnectionTermination";
119
  constexpr static absl::string_view UPSTREAM_OVERFLOW_LONG = "UpstreamOverflow";
120
  constexpr static absl::string_view UPSTREAM_RETRY_LIMIT_EXCEEDED_LONG =
121
      "UpstreamRetryLimitExceeded";
122
  constexpr static absl::string_view NO_ROUTE_FOUND_LONG = "NoRouteFound";
123
  constexpr static absl::string_view DELAY_INJECTED_LONG = "DelayInjected";
124
  constexpr static absl::string_view FAULT_INJECTED_LONG = "FaultInjected";
125
  constexpr static absl::string_view RATE_LIMITED_LONG = "RateLimited";
126
  constexpr static absl::string_view UNAUTHORIZED_EXTERNAL_SERVICE_LONG =
127
      "UnauthorizedExternalService";
128
  constexpr static absl::string_view RATELIMIT_SERVICE_ERROR_LONG = "RateLimitServiceError";
129
  constexpr static absl::string_view STREAM_IDLE_TIMEOUT_LONG = "StreamIdleTimeout";
130
  constexpr static absl::string_view INVALID_ENVOY_REQUEST_HEADERS_LONG =
131
      "InvalidEnvoyRequestHeaders";
132
  constexpr static absl::string_view DOWNSTREAM_PROTOCOL_ERROR_LONG = "DownstreamProtocolError";
133
  constexpr static absl::string_view UPSTREAM_MAX_STREAM_DURATION_REACHED_LONG =
134
      "UpstreamMaxStreamDurationReached";
135
  constexpr static absl::string_view RESPONSE_FROM_CACHE_FILTER_LONG = "ResponseFromCacheFilter";
136
  constexpr static absl::string_view NO_FILTER_CONFIG_FOUND_LONG = "NoFilterConfigFound";
137
  constexpr static absl::string_view DURATION_TIMEOUT_LONG = "DurationTimeout";
138
  constexpr static absl::string_view UPSTREAM_PROTOCOL_ERROR_LONG = "UpstreamProtocolError";
139
  constexpr static absl::string_view NO_CLUSTER_FOUND_LONG = "NoClusterFound";
140
  constexpr static absl::string_view OVERLOAD_MANAGER_LONG = "OverloadManagerTerminated";
141
  constexpr static absl::string_view DNS_FAIL_LONG = "DnsResolutionFailed";
142
  constexpr static absl::string_view DROP_OVERLOAD_LONG = "DropOverload";
143
  constexpr static absl::string_view DOWNSTREAM_REMOTE_RESET_LONG = "DownstreamRemoteReset";
144
  constexpr static absl::string_view UNCONDITIONAL_DROP_OVERLOAD_LONG = "UnconditionalDropOverload";
145

            
146
  static constexpr std::array CORE_RESPONSE_FLAGS{
147
      FlagStrings{FAILED_LOCAL_HEALTH_CHECK, FAILED_LOCAL_HEALTH_CHECK_LONG,
148
                  CoreResponseFlag::FailedLocalHealthCheck},
149
      FlagStrings{NO_HEALTHY_UPSTREAM, NO_HEALTHY_UPSTREAM_LONG,
150
                  CoreResponseFlag::NoHealthyUpstream},
151
      FlagStrings{UPSTREAM_REQUEST_TIMEOUT, UPSTREAM_REQUEST_TIMEOUT_LONG,
152
                  CoreResponseFlag::UpstreamRequestTimeout},
153
      FlagStrings{LOCAL_RESET, LOCAL_RESET_LONG, CoreResponseFlag::LocalReset},
154
      FlagStrings{UPSTREAM_REMOTE_RESET, UPSTREAM_REMOTE_RESET_LONG,
155
                  CoreResponseFlag::UpstreamRemoteReset},
156
      FlagStrings{UPSTREAM_CONNECTION_FAILURE, UPSTREAM_CONNECTION_FAILURE_LONG,
157
                  CoreResponseFlag::UpstreamConnectionFailure},
158
      FlagStrings{UPSTREAM_CONNECTION_TERMINATION, UPSTREAM_CONNECTION_TERMINATION_LONG,
159
                  CoreResponseFlag::UpstreamConnectionTermination},
160
      FlagStrings{UPSTREAM_OVERFLOW, UPSTREAM_OVERFLOW_LONG, CoreResponseFlag::UpstreamOverflow},
161
      FlagStrings{NO_ROUTE_FOUND, NO_ROUTE_FOUND_LONG, CoreResponseFlag::NoRouteFound},
162
      FlagStrings{DELAY_INJECTED, DELAY_INJECTED_LONG, CoreResponseFlag::DelayInjected},
163
      FlagStrings{FAULT_INJECTED, FAULT_INJECTED_LONG, CoreResponseFlag::FaultInjected},
164
      FlagStrings{RATE_LIMITED, RATE_LIMITED_LONG, CoreResponseFlag::RateLimited},
165
      FlagStrings{UNAUTHORIZED_EXTERNAL_SERVICE, UNAUTHORIZED_EXTERNAL_SERVICE_LONG,
166
                  CoreResponseFlag::UnauthorizedExternalService},
167
      FlagStrings{RATELIMIT_SERVICE_ERROR, RATELIMIT_SERVICE_ERROR_LONG,
168
                  CoreResponseFlag::RateLimitServiceError},
169
      FlagStrings{DOWNSTREAM_CONNECTION_TERMINATION, DOWNSTREAM_CONNECTION_TERMINATION_LONG,
170
                  CoreResponseFlag::DownstreamConnectionTermination},
171
      FlagStrings{UPSTREAM_RETRY_LIMIT_EXCEEDED, UPSTREAM_RETRY_LIMIT_EXCEEDED_LONG,
172
                  CoreResponseFlag::UpstreamRetryLimitExceeded},
173
      FlagStrings{STREAM_IDLE_TIMEOUT, STREAM_IDLE_TIMEOUT_LONG,
174
                  CoreResponseFlag::StreamIdleTimeout},
175
      FlagStrings{INVALID_ENVOY_REQUEST_HEADERS, INVALID_ENVOY_REQUEST_HEADERS_LONG,
176
                  CoreResponseFlag::InvalidEnvoyRequestHeaders},
177
      FlagStrings{DOWNSTREAM_PROTOCOL_ERROR, DOWNSTREAM_PROTOCOL_ERROR_LONG,
178
                  CoreResponseFlag::DownstreamProtocolError},
179
      FlagStrings{UPSTREAM_MAX_STREAM_DURATION_REACHED, UPSTREAM_MAX_STREAM_DURATION_REACHED_LONG,
180
                  CoreResponseFlag::UpstreamMaxStreamDurationReached},
181
      FlagStrings{RESPONSE_FROM_CACHE_FILTER, RESPONSE_FROM_CACHE_FILTER_LONG,
182
                  CoreResponseFlag::ResponseFromCacheFilter},
183
      FlagStrings{NO_FILTER_CONFIG_FOUND, NO_FILTER_CONFIG_FOUND_LONG,
184
                  CoreResponseFlag::NoFilterConfigFound},
185
      FlagStrings{DURATION_TIMEOUT, DURATION_TIMEOUT_LONG, CoreResponseFlag::DurationTimeout},
186
      FlagStrings{UPSTREAM_PROTOCOL_ERROR, UPSTREAM_PROTOCOL_ERROR_LONG,
187
                  CoreResponseFlag::UpstreamProtocolError},
188
      FlagStrings{NO_CLUSTER_FOUND, NO_CLUSTER_FOUND_LONG, CoreResponseFlag::NoClusterFound},
189
      FlagStrings{OVERLOAD_MANAGER, OVERLOAD_MANAGER_LONG, CoreResponseFlag::OverloadManager},
190
      FlagStrings{DNS_FAIL, DNS_FAIL_LONG, CoreResponseFlag::DnsResolutionFailed},
191
      FlagStrings{DROP_OVERLOAD, DROP_OVERLOAD_LONG, CoreResponseFlag::DropOverLoad},
192
      FlagStrings{DOWNSTREAM_REMOTE_RESET, DOWNSTREAM_REMOTE_RESET_LONG,
193
                  CoreResponseFlag::DownstreamRemoteReset},
194
      FlagStrings{UNCONDITIONAL_DROP_OVERLOAD, UNCONDITIONAL_DROP_OVERLOAD_LONG,
195
                  CoreResponseFlag::UnconditionalDropOverload},
196
  };
197

            
198
private:
199
  friend class CustomResponseFlag;
200

            
201
  static const std::string toString(const StreamInfo& stream_info, bool use_long_name);
202

            
203
  /**
204
   * Register a custom response flag.
205
   * @param flag supplies the flag to register. It should be an all upper case string with only
206
   * multiple characters.
207
   * @param flag_long supplies the long name of the flag to register. It should be PascalCase
208
   * string.
209
   * @return uint16_t the flag value.
210
   */
211
  static ResponseFlag registerCustomFlag(absl::string_view flag, absl::string_view flag_long);
212
  static ResponseFlagsMapType& mutableResponseFlagsMap();
213
};
214

            
215
class TimingUtility {
216
public:
217
243
  TimingUtility(const StreamInfo& info) : stream_info_(info) {}
218

            
219
  absl::optional<std::chrono::nanoseconds> firstUpstreamTxByteSent();
220
  absl::optional<std::chrono::nanoseconds> lastUpstreamTxByteSent();
221
  absl::optional<std::chrono::nanoseconds> firstUpstreamRxByteReceived();
222
  absl::optional<std::chrono::nanoseconds> lastUpstreamRxByteReceived();
223
  absl::optional<std::chrono::nanoseconds> firstUpstreamRxBodyByteReceived();
224
  absl::optional<std::chrono::nanoseconds> upstreamHandshakeComplete();
225
  absl::optional<std::chrono::nanoseconds> firstDownstreamTxByteSent();
226
  absl::optional<std::chrono::nanoseconds> lastDownstreamTxByteSent();
227
  absl::optional<std::chrono::nanoseconds> lastDownstreamHeaderRxByteReceived();
228
  absl::optional<std::chrono::nanoseconds> lastDownstreamRxByteReceived();
229
  absl::optional<std::chrono::nanoseconds> downstreamHandshakeComplete();
230
  absl::optional<std::chrono::nanoseconds> lastDownstreamAckReceived();
231

            
232
private:
233
  const StreamInfo& stream_info_;
234
};
235

            
236
/**
237
 * Utility class for StreamInfo.
238
 */
239
class Utility {
240
public:
241
  /**
242
   * @param address supplies the downstream address.
243
   * @param mask_prefix_len optional CIDR prefix length to mask the address. If not provided,
244
   * returns the unmasked IP address (without port).
245
   * @return the IP address without port, or masked IP address in CIDR notation if mask_prefix_len
246
   * is specified (e.g., "10.1.0.0/16"), or empty string if masking fails.
247
   */
248
  static const std::string
249
  formatDownstreamAddressNoPort(const Network::Address::Instance& address,
250
                                absl::optional<int> mask_prefix_len = absl::nullopt);
251

            
252
  /**
253
   * @param address supplies the downstream address.
254
   * @return a port, extracted from the provided downstream address for logs, header expansion, etc.
255
   */
256
  static const std::string
257
  formatDownstreamAddressJustPort(const Network::Address::Instance& address);
258

            
259
  /**
260
   * @param address supplies the downstream address.
261
   * @return a port, extracted from the provided downstream address for logs, header expansion, etc.
262
   */
263
  static absl::optional<uint32_t>
264
  extractDownstreamAddressJustPort(const Network::Address::Instance& address);
265

            
266
  /**
267
   * @param address supplies the downstream address.
268
   * @return the endpoint id of an EnvoyInternalAddress, extracted from the provided downstream
269
   * address for logs, header expansion, etc.
270
   */
271
  static const std::string
272
  formatDownstreamAddressJustEndpointId(const Network::Address::Instance& address);
273
};
274

            
275
// Static utils for creating, consuming, and producing strings from the
276
// Proxy-Status HTTP response header.
277
class ProxyStatusUtils {
278
public:
279
  // Returns a Proxy-Status proxy name string, configured according to |proxy_status_config|.
280
  // If |proxy_status_config| has not been set, defaults to |server_name|.
281
  static const std::string
282
  makeProxyName(absl::string_view node_id, absl::string_view server_name,
283
                const envoy::extensions::filters::network::http_connection_manager::v3::
284
                    HttpConnectionManager::ProxyStatusConfig* proxy_status_config);
285

            
286
  // Returns a Proxy-Status request header string, of the form:
287
  //
288
  //     <server_name>; error=<error_type>; details=<details>
289
  //
290
  // where:
291
  //   - node_id     is either the method argument, or the name of the proxy
292
  //                 in |node_id|,
293
  //   - error       is the error in |error|,
294
  //   - details     is |stream_info.responseCodeDetails()|, but the field is
295
  //                 present only if configured in |proxy_status_config|.
296
  static const std::string
297
  makeProxyStatusHeader(const StreamInfo& stream_info, ProxyStatusError error,
298
                        absl::string_view proxy_name,
299
                        const envoy::extensions::filters::network::http_connection_manager::v3::
300
                            HttpConnectionManager::ProxyStatusConfig& proxy_status_config);
301

            
302
  // Returns a view into the string representation of a given ProxyStatusError
303
  // enum.
304
  static const absl::string_view proxyStatusErrorToString(ProxyStatusError proxy_status);
305

            
306
  // Reads |stream_info.responseFlag| and returns an applicable ProxyStatusError, or nullopt
307
  // if no ProxyStatusError is applicable.
308
  static const absl::optional<ProxyStatusError> fromStreamInfo(const StreamInfo& stream_info);
309

            
310
  // Returns the recommended HTTP status code for a ProxyStatusError, or nullopt
311
  // if no HTTP status code is applicable.
312
  //
313
  // See
314
  // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-proxy-status-05#section-2.1.1 :
315
  //
316
  // > Each Proxy Error Type has a Recommended HTTP Status Code. When
317
  // > generating a HTTP response containing "error", its HTTP status code
318
  // > SHOULD be set to the Recommended HTTP Status Code.
319
  static const absl::optional<Http::Code>
320
  recommendedHttpStatusCode(const ProxyStatusError proxy_status);
321

            
322
  constexpr static absl::string_view DNS_TIMEOUT = "dns_timeout";
323
  constexpr static absl::string_view DNS_ERROR = "dns_error";
324
  constexpr static absl::string_view DESTINATION_NOT_FOUND = "destination_not_found";
325
  constexpr static absl::string_view DESTINATION_UNAVAILABLE = "destination_unavailable";
326
  constexpr static absl::string_view DESTINATION_IP_PROHIBITED = "destination_ip_prohibited";
327
  constexpr static absl::string_view DESTINATION_IP_UNROUTABLE = "destination_ip_unroutable";
328
  constexpr static absl::string_view CONNECTION_REFUSED = "connection_refused";
329
  constexpr static absl::string_view CONNECTION_TERMINATED = "connection_terminated";
330
  constexpr static absl::string_view CONNECTION_TIMEOUT = "connection_timeout";
331
  constexpr static absl::string_view CONNECTION_READ_TIMEOUT = "connection_read_timeout";
332
  constexpr static absl::string_view CONNECTION_WRITE_TIMEOUT = "connection_write_timeout";
333
  constexpr static absl::string_view CONNECTION_LIMIT_REACHED = "connection_limit_reached";
334
  constexpr static absl::string_view TLS_PROTOCOL_ERROR = "tls_protocol_error";
335
  constexpr static absl::string_view TLS_CERTIFICATE_ERROR = "tls_certificate_error";
336
  constexpr static absl::string_view TLS_ALERT_RECEIVED = "tls_alert_received";
337
  constexpr static absl::string_view HTTP_REQUEST_ERROR = "http_request_error";
338
  constexpr static absl::string_view HTTP_REQUEST_DENIED = "http_request_denied";
339
  constexpr static absl::string_view HTTP_RESPONSE_INCOMPLETE = "http_response_incomplete";
340
  constexpr static absl::string_view HTTP_RESPONSE_HEADER_SECTION_SIZE =
341
      "http_response_header_section_size";
342
  constexpr static absl::string_view HTTP_RESPONSE_HEADER_SIZE = "http_response_header_size";
343
  constexpr static absl::string_view HTTP_RESPONSE_BODY_SIZE = "http_response_body_size";
344
  constexpr static absl::string_view HTTP_RESPONSE_TRAILER_SECTION_SIZE =
345
      "http_response_trailer_section_size";
346
  constexpr static absl::string_view HTTP_RESPONSE_TRAILER_SIZE = "http_response_trailer_size";
347
  constexpr static absl::string_view HTTP_RESPONSE_TRANSFER_CODING =
348
      "http_response_transfer_coding";
349
  constexpr static absl::string_view HTTP_RESPONSE_CONTENT_CODING = "http_response_content_coding";
350
  constexpr static absl::string_view HTTP_RESPONSE_TIMEOUT = "http_response_timeout";
351
  constexpr static absl::string_view HTTP_UPGRADE_FAILED = "http_upgrade_failed";
352
  constexpr static absl::string_view HTTP_PROTOCOL_ERROR = "http_protocol_error";
353
  constexpr static absl::string_view PROXY_INTERNAL_RESPONSE = "proxy_internal_response";
354
  constexpr static absl::string_view PROXY_INTERNAL_ERROR = "proxy_internal_error";
355
  constexpr static absl::string_view PROXY_CONFIGURATION_ERROR = "proxy_configuration_error";
356
  constexpr static absl::string_view PROXY_LOOP_DETECTED = "proxy_loop_detected";
357
};
358

            
359
} // namespace StreamInfo
360
} // namespace Envoy