/proc/self/cwd/source/extensions/upstreams/http/config.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "source/extensions/upstreams/http/config.h" |
2 | | |
3 | | #include <chrono> |
4 | | #include <memory> |
5 | | #include <string> |
6 | | #include <vector> |
7 | | |
8 | | #include "envoy/config/cluster/v3/cluster.pb.h" |
9 | | #include "envoy/config/core/v3/base.pb.h" |
10 | | #include "envoy/extensions/http/header_validators/envoy_default/v3/header_validator.pb.h" |
11 | | #include "envoy/http/header_validator_factory.h" |
12 | | #include "envoy/upstream/upstream.h" |
13 | | |
14 | | #include "source/common/config/utility.h" |
15 | | #include "source/common/http/http1/settings.h" |
16 | | #include "source/common/http/utility.h" |
17 | | #include "source/common/protobuf/utility.h" |
18 | | |
19 | | namespace Envoy { |
20 | | namespace Extensions { |
21 | | namespace Upstreams { |
22 | | namespace Http { |
23 | | namespace { |
24 | | |
25 | | const envoy::config::core::v3::Http1ProtocolOptions& |
26 | 1.54k | getHttpOptions(const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options) { |
27 | 1.54k | if (options.has_use_downstream_protocol_config()) { |
28 | 0 | return options.use_downstream_protocol_config().http_protocol_options(); |
29 | 0 | } |
30 | 1.54k | if (options.has_auto_config()) { |
31 | 0 | return options.auto_config().http_protocol_options(); |
32 | 0 | } |
33 | 1.54k | return options.explicit_http_config().http_protocol_options(); |
34 | 1.54k | } |
35 | | |
36 | | const envoy::config::core::v3::Http2ProtocolOptions& |
37 | 1.54k | getHttp2Options(const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options) { |
38 | 1.54k | if (options.has_use_downstream_protocol_config()) { |
39 | 0 | return options.use_downstream_protocol_config().http2_protocol_options(); |
40 | 0 | } |
41 | 1.54k | if (options.has_auto_config()) { |
42 | 0 | return options.auto_config().http2_protocol_options(); |
43 | 0 | } |
44 | 1.54k | return options.explicit_http_config().http2_protocol_options(); |
45 | 1.54k | } |
46 | | |
47 | | const envoy::config::core::v3::Http3ProtocolOptions& |
48 | 1.54k | getHttp3Options(const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options) { |
49 | 1.54k | if (options.has_use_downstream_protocol_config() && |
50 | 1.54k | options.use_downstream_protocol_config().has_http3_protocol_options()) { |
51 | 0 | return options.use_downstream_protocol_config().http3_protocol_options(); |
52 | 0 | } |
53 | 1.54k | if (options.has_auto_config()) { |
54 | 0 | return options.auto_config().http3_protocol_options(); |
55 | 0 | } |
56 | 1.54k | return options.explicit_http_config().http3_protocol_options(); |
57 | 1.54k | } |
58 | | |
59 | 1.54k | bool useHttp2(const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options) { |
60 | 1.54k | if (options.has_explicit_http_config() && |
61 | 1.54k | options.explicit_http_config().has_http2_protocol_options()) { |
62 | 1.54k | return true; |
63 | 1.54k | } else if (options.has_use_downstream_protocol_config() && |
64 | 0 | options.use_downstream_protocol_config().has_http2_protocol_options()) { |
65 | 0 | return true; |
66 | 0 | } else if (options.has_auto_config()) { |
67 | 0 | return true; |
68 | 0 | } |
69 | 0 | return false; |
70 | 1.54k | } |
71 | | |
72 | 1.54k | bool useHttp3(const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options) { |
73 | 1.54k | if (options.has_explicit_http_config() && |
74 | 1.54k | options.explicit_http_config().has_http3_protocol_options()) { |
75 | 0 | return true; |
76 | 1.54k | } else if (options.has_use_downstream_protocol_config() && |
77 | 1.54k | options.use_downstream_protocol_config().has_http3_protocol_options()) { |
78 | 0 | return true; |
79 | 1.54k | } else if (options.has_auto_config() && options.auto_config().has_http3_protocol_options()) { |
80 | 0 | return true; |
81 | 0 | } |
82 | 1.54k | return false; |
83 | 1.54k | } |
84 | | |
85 | | absl::StatusOr<absl::optional<const envoy::config::core::v3::AlternateProtocolsCacheOptions>> |
86 | | getAlternateProtocolsCacheOptions( |
87 | | const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options, |
88 | 1.54k | Server::Configuration::ServerFactoryContext& server_context) { |
89 | 1.54k | if (options.has_auto_config() && options.auto_config().has_http3_protocol_options()) { |
90 | 0 | if (!options.auto_config().has_alternate_protocols_cache_options()) { |
91 | 0 | return absl::InvalidArgumentError( |
92 | 0 | fmt::format("alternate protocols cache must be configured when HTTP/3 " |
93 | 0 | "is enabled with auto_config")); |
94 | 0 | } |
95 | 0 | auto cache_options = options.auto_config().alternate_protocols_cache_options(); |
96 | 0 | if (cache_options.has_key_value_store_config() && server_context.options().concurrency() != 1) { |
97 | 0 | return absl::InvalidArgumentError( |
98 | 0 | fmt::format("options has key value store but Envoy has concurrency = {} : {}", |
99 | 0 | server_context.options().concurrency(), cache_options.DebugString())); |
100 | 0 | } |
101 | | |
102 | 0 | return cache_options; |
103 | 0 | } |
104 | 1.54k | return absl::nullopt; |
105 | 1.54k | } |
106 | | |
107 | | absl::StatusOr<Envoy::Http::HeaderValidatorFactoryPtr> createHeaderValidatorFactory( |
108 | | [[maybe_unused]] const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options, |
109 | 1.54k | [[maybe_unused]] Server::Configuration::ServerFactoryContext& server_context) { |
110 | | |
111 | 1.54k | Envoy::Http::HeaderValidatorFactoryPtr header_validator_factory; |
112 | | #ifdef ENVOY_ENABLE_UHV |
113 | | if (!Runtime::runtimeFeatureEnabled( |
114 | | "envoy.reloadable_features.enable_universal_header_validator")) { |
115 | | // This will cause codecs to use legacy header validation and path normalization |
116 | | return nullptr; |
117 | | } |
118 | | ::envoy::config::core::v3::TypedExtensionConfig legacy_header_validator_config; |
119 | | if (!options.has_header_validation_config()) { |
120 | | // If header validator is not configured ensure that the defaults match Envoy's original |
121 | | // behavior. |
122 | | ::envoy::extensions::http::header_validators::envoy_default::v3::HeaderValidatorConfig |
123 | | uhv_config; |
124 | | uhv_config.mutable_http1_protocol_options()->set_allow_chunked_length( |
125 | | getHttpOptions(options).allow_chunked_length()); |
126 | | legacy_header_validator_config.set_name("default_envoy_uhv_from_legacy_settings"); |
127 | | legacy_header_validator_config.mutable_typed_config()->PackFrom(uhv_config); |
128 | | } |
129 | | |
130 | | const ::envoy::config::core::v3::TypedExtensionConfig& header_validator_config = |
131 | | options.has_header_validation_config() ? options.header_validation_config() |
132 | | : legacy_header_validator_config; |
133 | | |
134 | | auto* factory = Envoy::Config::Utility::getFactory<Envoy::Http::HeaderValidatorFactoryConfig>( |
135 | | header_validator_config); |
136 | | if (!factory) { |
137 | | return absl::InvalidArgumentError( |
138 | | fmt::format("Header validator extension not found: '{}'", header_validator_config.name())); |
139 | | } |
140 | | |
141 | | header_validator_factory = |
142 | | factory->createFromProto(header_validator_config.typed_config(), server_context); |
143 | | if (!header_validator_factory) { |
144 | | return absl::InvalidArgumentError(fmt::format( |
145 | | "Header validator extension could not be created: '{}'", header_validator_config.name())); |
146 | | } |
147 | | #else |
148 | 1.54k | if (options.has_header_validation_config()) { |
149 | 0 | return absl::InvalidArgumentError( |
150 | 0 | fmt::format("This Envoy binary does not support header validator extensions: '{}'", |
151 | 0 | options.header_validation_config().name())); |
152 | 0 | } |
153 | | |
154 | 1.54k | if (Runtime::runtimeFeatureEnabled( |
155 | 1.54k | "envoy.reloadable_features.enable_universal_header_validator")) { |
156 | 0 | return absl::InvalidArgumentError( |
157 | 0 | "Header validator can not be enabled since this Envoy binary does not support it."); |
158 | 0 | } |
159 | 1.54k | #endif |
160 | 1.54k | return header_validator_factory; |
161 | 1.54k | } |
162 | | |
163 | | } // namespace |
164 | | |
165 | | uint64_t ProtocolOptionsConfigImpl::parseFeatures(const envoy::config::cluster::v3::Cluster& config, |
166 | 2.40k | const ProtocolOptionsConfigImpl& options) { |
167 | 2.40k | uint64_t features = 0; |
168 | | |
169 | 2.40k | if (options.use_http2_) { |
170 | 1.54k | features |= Upstream::ClusterInfo::Features::HTTP2; |
171 | 1.54k | } |
172 | 2.40k | if (options.use_http3_) { |
173 | 0 | features |= Upstream::ClusterInfo::Features::HTTP3; |
174 | 0 | } |
175 | 2.40k | if (options.use_downstream_protocol_) { |
176 | 0 | features |= Upstream::ClusterInfo::Features::USE_DOWNSTREAM_PROTOCOL; |
177 | 0 | } |
178 | 2.40k | if (options.use_alpn_) { |
179 | 0 | features |= Upstream::ClusterInfo::Features::USE_ALPN; |
180 | 0 | } |
181 | 2.40k | if (config.close_connections_on_host_health_failure()) { |
182 | 0 | features |= Upstream::ClusterInfo::Features::CLOSE_CONNECTIONS_ON_HOST_HEALTH_FAILURE; |
183 | 0 | } |
184 | 2.40k | return features; |
185 | 2.40k | } |
186 | | |
187 | | absl::StatusOr<std::shared_ptr<ProtocolOptionsConfigImpl>> |
188 | | ProtocolOptionsConfigImpl::createProtocolOptionsConfig( |
189 | | const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options, |
190 | 1.54k | Server::Configuration::ServerFactoryContext& server_context) { |
191 | 1.54k | auto options_or_error = Http2::Utility::initializeAndValidateOptions(getHttp2Options(options)); |
192 | 1.54k | RETURN_IF_NOT_OK_REF(options_or_error.status()); |
193 | 1.54k | auto cache_options_or_error = getAlternateProtocolsCacheOptions(options, server_context); |
194 | 1.54k | RETURN_IF_NOT_OK_REF(cache_options_or_error.status()); |
195 | 1.54k | auto validator_factory_or_error = createHeaderValidatorFactory(options, server_context); |
196 | 1.54k | RETURN_IF_NOT_OK_REF(validator_factory_or_error.status()); |
197 | 1.54k | return std::shared_ptr<ProtocolOptionsConfigImpl>(new ProtocolOptionsConfigImpl( |
198 | 1.54k | options, options_or_error.value(), std::move(validator_factory_or_error.value()), |
199 | 1.54k | cache_options_or_error.value(), server_context)); |
200 | 1.54k | } |
201 | | |
202 | | absl::StatusOr<std::shared_ptr<ProtocolOptionsConfigImpl>> |
203 | | ProtocolOptionsConfigImpl::createProtocolOptionsConfig( |
204 | | const envoy::config::core::v3::Http1ProtocolOptions& http1_settings, |
205 | | const envoy::config::core::v3::Http2ProtocolOptions& http2_options, |
206 | | const envoy::config::core::v3::HttpProtocolOptions& common_options, |
207 | | const absl::optional<envoy::config::core::v3::UpstreamHttpProtocolOptions> upstream_options, |
208 | | bool use_downstream_protocol, bool use_http2, |
209 | 862 | ProtobufMessage::ValidationVisitor& validation_visitor) { |
210 | 862 | auto options_or_error = Http2::Utility::initializeAndValidateOptions(http2_options); |
211 | 862 | RETURN_IF_NOT_OK_REF(options_or_error.status()); |
212 | 862 | return std::shared_ptr<ProtocolOptionsConfigImpl>(new ProtocolOptionsConfigImpl( |
213 | 862 | http1_settings, options_or_error.value(), common_options, upstream_options, |
214 | 862 | use_downstream_protocol, use_http2, validation_visitor)); |
215 | 862 | } |
216 | | |
217 | | ProtocolOptionsConfigImpl::ProtocolOptionsConfigImpl( |
218 | | const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options, |
219 | | envoy::config::core::v3::Http2ProtocolOptions http2_options, |
220 | | Envoy::Http::HeaderValidatorFactoryPtr&& header_validator_factory, |
221 | | absl::optional<const envoy::config::core::v3::AlternateProtocolsCacheOptions> cache_options, |
222 | | Server::Configuration::ServerFactoryContext& server_context) |
223 | | : http1_settings_(Envoy::Http::Http1::parseHttp1Settings( |
224 | | getHttpOptions(options), server_context.messageValidationVisitor())), |
225 | | http2_options_(std::move(http2_options)), http3_options_(getHttp3Options(options)), |
226 | | common_http_protocol_options_(options.common_http_protocol_options()), |
227 | | upstream_http_protocol_options_( |
228 | | options.has_upstream_http_protocol_options() |
229 | | ? absl::make_optional<envoy::config::core::v3::UpstreamHttpProtocolOptions>( |
230 | | options.upstream_http_protocol_options()) |
231 | | : absl::nullopt), |
232 | | http_filters_(options.http_filters()), |
233 | | alternate_protocol_cache_options_(std::move(cache_options)), |
234 | | header_validator_factory_(std::move(header_validator_factory)), |
235 | | use_downstream_protocol_(options.has_use_downstream_protocol_config()), |
236 | | use_http2_(useHttp2(options)), use_http3_(useHttp3(options)), |
237 | 1.54k | use_alpn_(options.has_auto_config()) { |
238 | 1.54k | ASSERT(Http2::Utility::initializeAndValidateOptions(http2_options_).status().ok()); |
239 | 1.54k | } |
240 | | |
241 | | ProtocolOptionsConfigImpl::ProtocolOptionsConfigImpl( |
242 | | const envoy::config::core::v3::Http1ProtocolOptions& http1_settings, |
243 | | const envoy::config::core::v3::Http2ProtocolOptions& validated_http2_options, |
244 | | const envoy::config::core::v3::HttpProtocolOptions& common_options, |
245 | | const absl::optional<envoy::config::core::v3::UpstreamHttpProtocolOptions> upstream_options, |
246 | | bool use_downstream_protocol, bool use_http2, |
247 | | ProtobufMessage::ValidationVisitor& validation_visitor) |
248 | | : http1_settings_(Envoy::Http::Http1::parseHttp1Settings(http1_settings, validation_visitor)), |
249 | | http2_options_(validated_http2_options), common_http_protocol_options_(common_options), |
250 | | upstream_http_protocol_options_(upstream_options), |
251 | 862 | use_downstream_protocol_(use_downstream_protocol), use_http2_(use_http2) { |
252 | 862 | ASSERT(Http2::Utility::initializeAndValidateOptions(validated_http2_options).status().ok()); |
253 | 862 | } |
254 | | |
255 | | LEGACY_REGISTER_FACTORY(ProtocolOptionsConfigFactory, Server::Configuration::ProtocolOptionsFactory, |
256 | | "envoy.upstreams.http.http_protocol_options"); |
257 | | } // namespace Http |
258 | | } // namespace Upstreams |
259 | | } // namespace Extensions |
260 | | } // namespace Envoy |