/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 |