Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/common/runtime/runtime_features.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/common/runtime/runtime_features.h"
2
3
#include "absl/flags/commandlineflag.h"
4
#include "absl/flags/flag.h"
5
#include "absl/strings/match.h"
6
#include "absl/strings/str_replace.h"
7
8
#define RUNTIME_GUARD(name) ABSL_FLAG(bool, name, true, "");        // NOLINT
9
#define FALSE_RUNTIME_GUARD(name) ABSL_FLAG(bool, name, false, ""); // NOLINT
10
11
// Add additional features here to enable the new code paths by default.
12
//
13
// Per documentation in CONTRIBUTING.md is expected that new high risk code paths be guarded
14
// by runtime feature guards. If you add a guard of the form
15
// RUNTIME_GUARD(envoy_reloadable_features_my_feature_name)
16
// here you can guard code checking against "envoy.reloadable_features.my_feature_name".
17
// Please note the swap of envoy_reloadable_features_ to envoy.reloadable_features.!
18
//
19
// if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.my_feature_name")) {
20
//   [new code path]
21
// else {
22
//   [old_code_path]
23
// }
24
//
25
// Runtime features are true by default, so the new code path is exercised.
26
// To make a runtime feature false by default, use FALSE_RUNTIME_GUARD, and add
27
// a TODO to change it to true.
28
//
29
// If issues are found that require a runtime feature to be disabled, it should be reported
30
// ASAP by filing a bug on github. Overriding non-buggy code is strongly discouraged to avoid the
31
// problem of the bugs being found after the old code path has been removed.
32
RUNTIME_GUARD(envoy_reloadable_features_allow_absolute_url_with_mixed_scheme);
33
RUNTIME_GUARD(envoy_reloadable_features_append_xfh_idempotent);
34
RUNTIME_GUARD(envoy_reloadable_features_check_mep_on_first_eject);
35
RUNTIME_GUARD(envoy_reloadable_features_conn_pool_delete_when_idle);
36
RUNTIME_GUARD(envoy_reloadable_features_convert_legacy_lb_config);
37
RUNTIME_GUARD(envoy_reloadable_features_copy_response_code_to_downstream_stream_info);
38
RUNTIME_GUARD(envoy_reloadable_features_count_unused_mapped_pages_as_free);
39
RUNTIME_GUARD(envoy_reloadable_features_defer_processing_backedup_streams);
40
RUNTIME_GUARD(envoy_reloadable_features_detect_and_raise_rst_tcp_connection);
41
RUNTIME_GUARD(envoy_reloadable_features_dfp_mixed_scheme);
42
RUNTIME_GUARD(envoy_reloadable_features_enable_aws_credentials_file);
43
RUNTIME_GUARD(envoy_reloadable_features_enable_compression_bomb_protection);
44
RUNTIME_GUARD(envoy_reloadable_features_enable_connect_udp_support);
45
RUNTIME_GUARD(envoy_reloadable_features_enable_intermediate_ca);
46
RUNTIME_GUARD(envoy_reloadable_features_enable_zone_routing_different_zone_counts);
47
RUNTIME_GUARD(envoy_reloadable_features_ext_authz_http_send_original_xff);
48
RUNTIME_GUARD(envoy_reloadable_features_handle_uppercase_scheme);
49
RUNTIME_GUARD(envoy_reloadable_features_hmac_base64_encoding_only);
50
RUNTIME_GUARD(envoy_reloadable_features_http1_allow_codec_error_response_after_1xx_headers);
51
RUNTIME_GUARD(envoy_reloadable_features_http1_connection_close_header_in_redirect);
52
RUNTIME_GUARD(envoy_reloadable_features_http1_use_balsa_parser);
53
RUNTIME_GUARD(envoy_reloadable_features_http2_decode_metadata_with_quiche);
54
RUNTIME_GUARD(envoy_reloadable_features_http2_validate_authority_with_quiche);
55
RUNTIME_GUARD(envoy_reloadable_features_http_allow_partial_urls_in_referer);
56
RUNTIME_GUARD(envoy_reloadable_features_http_filter_avoid_reentrant_local_reply);
57
// Delay deprecation and decommission until UHV is enabled.
58
RUNTIME_GUARD(envoy_reloadable_features_http_reject_path_with_fragment);
59
RUNTIME_GUARD(envoy_reloadable_features_ignore_optional_option_from_hcm_for_route_config);
60
RUNTIME_GUARD(envoy_reloadable_features_immediate_response_use_filter_mutation_rule);
61
RUNTIME_GUARD(envoy_reloadable_features_initialize_upstream_filters);
62
RUNTIME_GUARD(envoy_reloadable_features_keep_endpoint_active_hc_status_on_locality_update);
63
RUNTIME_GUARD(envoy_reloadable_features_locality_routing_use_new_routing_logic);
64
RUNTIME_GUARD(envoy_reloadable_features_lowercase_scheme);
65
RUNTIME_GUARD(envoy_reloadable_features_no_downgrade_to_canonical_name);
66
RUNTIME_GUARD(envoy_reloadable_features_no_extension_lookup_by_name);
67
RUNTIME_GUARD(envoy_reloadable_features_no_full_scan_certs_on_sni_mismatch);
68
RUNTIME_GUARD(envoy_reloadable_features_normalize_host_for_preresolve_dfp_dns);
69
RUNTIME_GUARD(envoy_reloadable_features_oauth_make_token_cookie_httponly);
70
RUNTIME_GUARD(envoy_reloadable_features_oauth_use_standard_max_age_value);
71
RUNTIME_GUARD(envoy_reloadable_features_oauth_use_url_encoding);
72
RUNTIME_GUARD(envoy_reloadable_features_original_dst_rely_on_idle_timeout);
73
RUNTIME_GUARD(envoy_reloadable_features_overload_manager_error_unknown_action);
74
RUNTIME_GUARD(envoy_reloadable_features_proxy_status_upstream_request_timeout);
75
RUNTIME_GUARD(envoy_reloadable_features_quic_fix_filter_manager_uaf);
76
RUNTIME_GUARD(envoy_reloadable_features_send_header_raw_value);
77
RUNTIME_GUARD(envoy_reloadable_features_skip_dns_lookup_for_proxied_requests);
78
RUNTIME_GUARD(envoy_reloadable_features_ssl_transport_failure_reason_format);
79
RUNTIME_GUARD(envoy_reloadable_features_stateful_session_encode_ttl_in_cookie);
80
RUNTIME_GUARD(envoy_reloadable_features_stop_decode_metadata_on_local_reply);
81
RUNTIME_GUARD(envoy_reloadable_features_test_feature_true);
82
RUNTIME_GUARD(envoy_reloadable_features_thrift_allow_negative_field_ids);
83
RUNTIME_GUARD(envoy_reloadable_features_thrift_connection_draining);
84
RUNTIME_GUARD(envoy_reloadable_features_token_passed_entirely);
85
RUNTIME_GUARD(envoy_reloadable_features_uhv_allow_malformed_url_encoding);
86
RUNTIME_GUARD(envoy_reloadable_features_upstream_allow_connect_with_2xx);
87
RUNTIME_GUARD(envoy_reloadable_features_upstream_wait_for_response_headers_before_disabling_read);
88
RUNTIME_GUARD(envoy_reloadable_features_use_cluster_cache_for_alt_protocols_filter);
89
RUNTIME_GUARD(envoy_reloadable_features_use_http3_header_normalisation);
90
RUNTIME_GUARD(envoy_reloadable_features_validate_connect);
91
RUNTIME_GUARD(envoy_reloadable_features_validate_grpc_header_before_log_grpc_status);
92
RUNTIME_GUARD(envoy_reloadable_features_validate_upstream_headers);
93
RUNTIME_GUARD(envoy_restart_features_send_goaway_for_premature_rst_streams);
94
RUNTIME_GUARD(envoy_restart_features_udp_read_normalize_addresses);
95
96
// Begin false flags. These should come with a TODO to flip true.
97
// Sentinel and test flag.
98
FALSE_RUNTIME_GUARD(envoy_reloadable_features_test_feature_false);
99
// TODO(paul-r-gall) Make this enabled by default after additional soak time.
100
FALSE_RUNTIME_GUARD(envoy_reloadable_features_streaming_shadow);
101
// TODO(adisuissa) reset to true to enable unified mux by default
102
FALSE_RUNTIME_GUARD(envoy_reloadable_features_unified_mux);
103
// TODO(birenroy) flip after a burn-in period
104
FALSE_RUNTIME_GUARD(envoy_reloadable_features_http2_use_oghttp2);
105
// Used to track if runtime is initialized.
106
FALSE_RUNTIME_GUARD(envoy_reloadable_features_runtime_initialized);
107
// TODO(mattklein123): Flip this to true and/or remove completely once verified by Envoy Mobile.
108
// TODO(mattklein123): Also unit test this if this sticks and this becomes the default for Apple &
109
// Android.
110
FALSE_RUNTIME_GUARD(envoy_reloadable_features_always_use_v6);
111
// TODO(pradeepcrao) reset this to true after 2 releases (1.27)
112
FALSE_RUNTIME_GUARD(envoy_reloadable_features_enable_include_histograms);
113
// TODO(wbpcode) complete remove this feature is no one use it.
114
FALSE_RUNTIME_GUARD(envoy_reloadable_features_refresh_rtt_after_request);
115
// TODO(danzh) false deprecate it once QUICHE has its own enable/disable flag.
116
FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_reject_all);
117
// TODO(suniltheta): Once the newly added http async technique proves effective and
118
// is stabilized get rid of this feature flag and code path that relies on libcurl.
119
FALSE_RUNTIME_GUARD(envoy_reloadable_features_use_libcurl_to_fetch_aws_credentials);
120
// TODO(adisuissa): enable by default once this is tested in prod.
121
FALSE_RUNTIME_GUARD(envoy_restart_features_use_eds_cache_for_ads);
122
// TODO(#10646) change to true when UHV is sufficiently tested
123
// For more information about Universal Header Validation, please see
124
// https://github.com/envoyproxy/envoy/issues/10646
125
FALSE_RUNTIME_GUARD(envoy_reloadable_features_enable_universal_header_validator);
126
// TODO(pksohn): enable after fixing https://github.com/envoyproxy/envoy/issues/29930
127
FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_defer_logging_to_ack_listener);
128
129
// Block of non-boolean flags. Use of int flags is deprecated. Do not add more.
130
ABSL_FLAG(uint64_t, re2_max_program_size_error_level, 100, ""); // NOLINT
131
ABSL_FLAG(uint64_t, re2_max_program_size_warn_level,            // NOLINT
132
          std::numeric_limits<uint32_t>::max(), "");            // NOLINT
133
134
namespace Envoy {
135
namespace Runtime {
136
namespace {
137
138
3.07k
std::string swapPrefix(std::string name) {
139
3.07k
  return absl::StrReplaceAll(name, {{"envoy_", "envoy."}, {"features_", "features."}});
140
3.07k
}
141
142
} // namespace
143
144
// This is a singleton class to map Envoy style flag names to absl flags
145
class RuntimeFeatures {
146
public:
147
  RuntimeFeatures();
148
149
  // Get the command line flag corresponding to the Envoy style feature name, or
150
  // nullptr if it is not a registered flag.
151
2.82M
  absl::CommandLineFlag* getFlag(absl::string_view feature) const {
152
2.82M
    auto it = all_features_.find(feature);
153
2.82M
    if (it == all_features_.end()) {
154
135k
      return nullptr;
155
135k
    }
156
2.68M
    return it->second;
157
2.82M
  }
158
159
private:
160
  absl::flat_hash_map<std::string, absl::CommandLineFlag*> all_features_;
161
};
162
163
using RuntimeFeaturesDefaults = ConstSingleton<RuntimeFeatures>;
164
165
41
RuntimeFeatures::RuntimeFeatures() {
166
41
  absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> flags = absl::GetAllFlags();
167
7.59k
  for (auto& it : flags) {
168
7.59k
    absl::string_view name = it.second->Name();
169
7.59k
    if ((!absl::StartsWith(name, "envoy_reloadable_features_") &&
170
7.59k
         !absl::StartsWith(name, "envoy_restart_features_")) ||
171
7.59k
        !it.second->TryGet<bool>().has_value()) {
172
4.51k
      continue;
173
4.51k
    }
174
3.07k
    std::string envoy_name = swapPrefix(std::string(name));
175
3.07k
    all_features_.emplace(envoy_name, it.second);
176
3.07k
  }
177
41
}
178
179
12.4k
bool hasRuntimePrefix(absl::string_view feature) {
180
  // Track Envoy reloadable and restart features, excluding synthetic QUIC flags
181
  // which are not tracked in the list below.
182
12.4k
  return (absl::StartsWith(feature, "envoy.reloadable_features.") &&
183
12.4k
          !absl::StartsWith(feature, "envoy.reloadable_features.FLAGS_envoy_quic")) ||
184
12.4k
         absl::StartsWith(feature, "envoy.restart_features.");
185
12.4k
}
186
187
187k
bool isRuntimeFeature(absl::string_view feature) {
188
187k
  return RuntimeFeaturesDefaults::get().getFlag(feature) != nullptr;
189
187k
}
190
191
2.47M
bool runtimeFeatureEnabled(absl::string_view feature) {
192
2.47M
  absl::CommandLineFlag* flag = RuntimeFeaturesDefaults::get().getFlag(feature);
193
2.47M
  if (flag == nullptr) {
194
0
    IS_ENVOY_BUG(absl::StrCat("Unable to find runtime feature ", feature));
195
0
    return false;
196
0
  }
197
  // We validate in map creation that the flag is a boolean.
198
2.47M
  return flag->TryGet<bool>().value();
199
2.47M
}
200
201
3.51k
uint64_t getInteger(absl::string_view feature, uint64_t default_value) {
202
  // DO NOT ADD MORE FLAGS HERE. This function deprecated.
203
3.51k
  if (absl::StartsWith(feature, "re2.")) {
204
3.51k
    if (feature == "re2.max_program_size.error_level") {
205
1.80k
      return absl::GetFlag(FLAGS_re2_max_program_size_error_level);
206
1.80k
    } else if (feature == "re2.max_program_size.warn_level") {
207
1.70k
      return absl::GetFlag(FLAGS_re2_max_program_size_warn_level);
208
1.70k
    }
209
3.51k
  }
210
0
  IS_ENVOY_BUG(absl::StrCat("requested an unsupported integer ", feature));
211
0
  return default_value;
212
0
}
213
214
110k
void markRuntimeInitialized() {
215
110k
  maybeSetRuntimeGuard("envoy.reloadable_features.runtime_initialized", true);
216
110k
}
217
218
15.0k
bool isRuntimeInitialized() {
219
15.0k
  return runtimeFeatureEnabled("envoy.reloadable_features.runtime_initialized");
220
15.0k
}
221
222
160k
void maybeSetRuntimeGuard(absl::string_view name, bool value) {
223
160k
  absl::CommandLineFlag* flag = RuntimeFeaturesDefaults::get().getFlag(name);
224
160k
  if (flag == nullptr) {
225
0
    IS_ENVOY_BUG(absl::StrCat("Unable to find runtime feature ", name));
226
0
    return;
227
0
  }
228
160k
  std::string err;
229
160k
  flag->ParseFrom(value ? "true" : "false", &err);
230
160k
}
231
232
6.27k
void maybeSetDeprecatedInts(absl::string_view name, uint32_t value) {
233
6.27k
  if (!absl::StartsWith(name, "envoy.") && !absl::StartsWith(name, "re2.")) {
234
5.93k
    return;
235
5.93k
  }
236
237
  // DO NOT ADD MORE FLAGS HERE. This function deprecated.
238
344
  else if (name == "re2.max_program_size.error_level") {
239
0
    absl::SetFlag(&FLAGS_re2_max_program_size_error_level, value);
240
344
  } else if (name == "re2.max_program_size.warn_level") {
241
0
    absl::SetFlag(&FLAGS_re2_max_program_size_warn_level, value);
242
0
  }
243
6.27k
}
244
245
} // namespace Runtime
246
} // namespace Envoy