Line data Source code
1 : #pragma once
2 :
3 : #include <chrono>
4 : #include <cstdint>
5 : #include <iterator>
6 : #include <list>
7 : #include <map>
8 : #include <memory>
9 : #include <regex>
10 : #include <string>
11 : #include <vector>
12 :
13 : #include "envoy/config/core/v3/base.pb.h"
14 : #include "envoy/config/route/v3/route.pb.h"
15 : #include "envoy/config/route/v3/route_components.pb.h"
16 : #include "envoy/config/route/v3/route_components.pb.validate.h"
17 : #include "envoy/registry/registry.h"
18 : #include "envoy/router/cluster_specifier_plugin.h"
19 : #include "envoy/router/router.h"
20 : #include "envoy/runtime/runtime.h"
21 : #include "envoy/server/filter_config.h"
22 : #include "envoy/type/v3/percent.pb.h"
23 : #include "envoy/upstream/cluster_manager.h"
24 :
25 : #include "source/common/common/matchers.h"
26 : #include "source/common/common/packed_struct.h"
27 : #include "source/common/config/metadata.h"
28 : #include "source/common/http/hash_policy.h"
29 : #include "source/common/http/header_utility.h"
30 : #include "source/common/matcher/matcher.h"
31 : #include "source/common/router/config_utility.h"
32 : #include "source/common/router/header_parser.h"
33 : #include "source/common/router/metadatamatchcriteria_impl.h"
34 : #include "source/common/router/router_ratelimit.h"
35 : #include "source/common/router/tls_context_match_criteria_impl.h"
36 : #include "source/common/stats/symbol_table.h"
37 :
38 : #include "absl/container/node_hash_map.h"
39 : #include "absl/types/optional.h"
40 :
41 : namespace Envoy {
42 : namespace Router {
43 :
44 : using RouteMetadataPack = Envoy::Config::MetadataPack<HttpRouteTypedMetadataFactory>;
45 : using RouteMetadataPackPtr = Envoy::Config::MetadataPackPtr<HttpRouteTypedMetadataFactory>;
46 : using DefaultRouteMetadataPack = ConstSingleton<RouteMetadataPack>;
47 :
48 : /**
49 : * Original port from the authority header.
50 : */
51 : class OriginalConnectPort : public StreamInfo::FilterState::Object {
52 : public:
53 0 : explicit OriginalConnectPort(uint32_t port) : port_(port) {}
54 0 : const uint32_t& value() const { return port_; }
55 : static const std::string& key();
56 :
57 : private:
58 : const uint32_t port_;
59 : };
60 :
61 : /**
62 : * Base interface for something that matches a header.
63 : */
64 : class Matchable {
65 : public:
66 1684 : virtual ~Matchable() = default;
67 :
68 : /**
69 : * See if this object matches the incoming headers.
70 : * @param headers supplies the headers to match.
71 : * @param random_value supplies the random seed to use if a runtime choice is required. This
72 : * allows stable choices between calls if desired.
73 : * @return true if input headers match this object.
74 : */
75 : virtual RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
76 : const StreamInfo::StreamInfo& stream_info,
77 : uint64_t random_value) const PURE;
78 :
79 : // By default, matchers do not support null Path headers.
80 0 : virtual bool supportsPathlessHeaders() const { return false; }
81 : };
82 :
83 : class PerFilterConfigs : public Logger::Loggable<Logger::Id::http> {
84 : public:
85 : struct FilterConfig {
86 : RouteSpecificFilterConfigConstSharedPtr config_;
87 : bool disabled_{};
88 : };
89 :
90 : PerFilterConfigs(const Protobuf::Map<std::string, ProtobufWkt::Any>& typed_configs,
91 : Server::Configuration::ServerFactoryContext& factory_context,
92 : ProtobufMessage::ValidationVisitor& validator);
93 :
94 : const RouteSpecificFilterConfig* get(const std::string& name) const;
95 :
96 : /**
97 : * @return true if the filter is explicitly disabled for this route or virtual host, false
98 : * if the filter is explicitly enabled. If the filter is not explicitly enabled or disabled,
99 : * returns absl::nullopt.
100 : */
101 : absl::optional<bool> disabled(absl::string_view name) const;
102 :
103 : private:
104 : RouteSpecificFilterConfigConstSharedPtr
105 : createRouteSpecificFilterConfig(const std::string& name, const ProtobufWkt::Any& typed_config,
106 : bool is_optional,
107 : Server::Configuration::ServerFactoryContext& factory_context,
108 : ProtobufMessage::ValidationVisitor& validator);
109 : absl::flat_hash_map<std::string, FilterConfig> configs_;
110 : };
111 :
112 : class RouteEntryImplBase;
113 : using RouteEntryImplBaseConstSharedPtr = std::shared_ptr<const RouteEntryImplBase>;
114 :
115 : /**
116 : * Direct response entry that does an SSL redirect.
117 : */
118 : class SslRedirector : public DirectResponseEntry {
119 : public:
120 : // Router::DirectResponseEntry
121 : void finalizeResponseHeaders(Http::ResponseHeaderMap&,
122 0 : const StreamInfo::StreamInfo&) const override {}
123 : Http::HeaderTransforms responseHeaderTransforms(const StreamInfo::StreamInfo&,
124 0 : bool) const override {
125 0 : return {};
126 0 : }
127 : std::string newUri(const Http::RequestHeaderMap& headers) const override;
128 0 : void rewritePathHeader(Http::RequestHeaderMap&, bool) const override {}
129 0 : Http::Code responseCode() const override { return Http::Code::MovedPermanently; }
130 0 : const std::string& responseBody() const override { return EMPTY_STRING; }
131 : };
132 :
133 : class SslRedirectRoute : public Route {
134 : public:
135 : // Router::Route
136 0 : const DirectResponseEntry* directResponseEntry() const override { return &SSL_REDIRECTOR; }
137 0 : const RouteEntry* routeEntry() const override { return nullptr; }
138 0 : const Decorator* decorator() const override { return nullptr; }
139 0 : const RouteTracing* tracingConfig() const override { return nullptr; }
140 0 : const RouteSpecificFilterConfig* mostSpecificPerFilterConfig(const std::string&) const override {
141 0 : return nullptr;
142 0 : }
143 0 : absl::optional<bool> filterDisabled(absl::string_view) const override { return {}; }
144 : void traversePerFilterConfig(
145 : const std::string&,
146 0 : std::function<void(const Router::RouteSpecificFilterConfig&)>) const override {}
147 0 : const envoy::config::core::v3::Metadata& metadata() const override { return metadata_; }
148 0 : const Envoy::Config::TypedMetadata& typedMetadata() const override { return typed_metadata_; }
149 0 : const std::string& routeName() const override { return EMPTY_STRING; }
150 :
151 : private:
152 : static const SslRedirector SSL_REDIRECTOR;
153 : static const envoy::config::core::v3::Metadata metadata_;
154 : static const Envoy::Config::TypedMetadataImpl<Envoy::Config::TypedMetadataFactory>
155 : typed_metadata_;
156 : };
157 :
158 : /**
159 : * Implementation of CorsPolicy that reads from the proto route and virtual host config.
160 : * TODO(wbpcode): move all cors interfaces and implementation to 'extensions/filters/http/cors'.
161 : */
162 : template <class ProtoType> class CorsPolicyImplBase : public CorsPolicy {
163 : public:
164 : CorsPolicyImplBase(const ProtoType& config, Runtime::Loader& loader)
165 : : config_(config), loader_(loader), allow_methods_(config.allow_methods()),
166 : allow_headers_(config.allow_headers()), expose_headers_(config.expose_headers()),
167 4 : max_age_(config.max_age()) {
168 4 : for (const auto& string_match : config.allow_origin_string_match()) {
169 4 : allow_origins_.push_back(
170 4 : std::make_unique<Matchers::StringMatcherImpl<envoy::type::matcher::v3::StringMatcher>>(
171 4 : string_match));
172 4 : }
173 4 : if (config.has_allow_credentials()) {
174 4 : allow_credentials_ = PROTOBUF_GET_WRAPPED_REQUIRED(config, allow_credentials);
175 4 : }
176 4 : if (config.has_allow_private_network_access()) {
177 2 : allow_private_network_access_ =
178 2 : PROTOBUF_GET_WRAPPED_REQUIRED(config, allow_private_network_access);
179 2 : }
180 4 : }
181 :
182 : // Router::CorsPolicy
183 0 : const std::vector<Matchers::StringMatcherPtr>& allowOrigins() const override {
184 0 : return allow_origins_;
185 0 : };
186 0 : const std::string& allowMethods() const override { return allow_methods_; };
187 0 : const std::string& allowHeaders() const override { return allow_headers_; };
188 0 : const std::string& exposeHeaders() const override { return expose_headers_; };
189 0 : const std::string& maxAge() const override { return max_age_; };
190 0 : const absl::optional<bool>& allowCredentials() const override { return allow_credentials_; };
191 0 : const absl::optional<bool>& allowPrivateNetworkAccess() const override {
192 0 : return allow_private_network_access_;
193 0 : };
194 0 : bool enabled() const override {
195 0 : if (config_.has_filter_enabled()) {
196 0 : const auto& filter_enabled = config_.filter_enabled();
197 0 : return loader_.snapshot().featureEnabled(filter_enabled.runtime_key(),
198 0 : filter_enabled.default_value());
199 0 : }
200 0 : return true;
201 0 : };
202 0 : bool shadowEnabled() const override {
203 0 : if (config_.has_shadow_enabled()) {
204 0 : const auto& shadow_enabled = config_.shadow_enabled();
205 0 : return loader_.snapshot().featureEnabled(shadow_enabled.runtime_key(),
206 0 : shadow_enabled.default_value());
207 0 : }
208 0 : return false;
209 0 : };
210 :
211 : private:
212 : const ProtoType config_;
213 : Runtime::Loader& loader_;
214 : std::vector<Matchers::StringMatcherPtr> allow_origins_;
215 : const std::string allow_methods_;
216 : const std::string allow_headers_;
217 : const std::string expose_headers_;
218 : const std::string max_age_;
219 : absl::optional<bool> allow_credentials_{};
220 : absl::optional<bool> allow_private_network_access_{};
221 : };
222 : using CorsPolicyImpl = CorsPolicyImplBase<envoy::config::route::v3::CorsPolicy>;
223 :
224 : using RetryPolicyConstOptRef = const OptRef<const envoy::config::route::v3::RetryPolicy>;
225 : using HedgePolicyConstOptRef = const OptRef<const envoy::config::route::v3::HedgePolicy>;
226 :
227 : class ConfigImpl;
228 : class CommonConfigImpl;
229 : using CommonConfigSharedPtr = std::shared_ptr<CommonConfigImpl>;
230 :
231 : /**
232 : * Implementation of VirtualHost that reads from the proto config. This class holds all shared
233 : * data for all routes in the virtual host.
234 : */
235 : class CommonVirtualHostImpl : public VirtualHost, Logger::Loggable<Logger::Id::router> {
236 : public:
237 : CommonVirtualHostImpl(const envoy::config::route::v3::VirtualHost& virtual_host,
238 : const CommonConfigSharedPtr& global_route_config,
239 : Server::Configuration::ServerFactoryContext& factory_context,
240 : Stats::Scope& scope, ProtobufMessage::ValidationVisitor& validator);
241 :
242 : const VirtualCluster* virtualClusterFromEntries(const Http::HeaderMap& headers) const;
243 3381 : const CommonConfigImpl& globalRouteConfig() const { return *global_route_config_; }
244 196 : const HeaderParser& requestHeaderParser() const {
245 196 : if (request_headers_parser_ != nullptr) {
246 1 : return *request_headers_parser_;
247 1 : }
248 195 : return HeaderParser::defaultParser();
249 196 : }
250 335 : const HeaderParser& responseHeaderParser() const {
251 335 : if (response_headers_parser_ != nullptr) {
252 0 : return *response_headers_parser_;
253 0 : }
254 335 : return HeaderParser::defaultParser();
255 335 : }
256 : absl::optional<bool> filterDisabled(absl::string_view config_name) const;
257 :
258 : // Router::VirtualHost
259 0 : const CorsPolicy* corsPolicy() const override { return cors_policy_.get(); }
260 209 : Stats::StatName statName() const override { return stat_name_storage_.statName(); }
261 0 : const RateLimitPolicy& rateLimitPolicy() const override {
262 0 : if (rate_limit_policy_ != nullptr) {
263 0 : return *rate_limit_policy_;
264 0 : }
265 0 : return DefaultRateLimitPolicy::get();
266 0 : }
267 : const CommonConfig& routeConfig() const override;
268 : const RouteSpecificFilterConfig* mostSpecificPerFilterConfig(const std::string&) const override;
269 183 : bool includeAttemptCountInRequest() const override { return include_attempt_count_in_request_; }
270 183 : bool includeAttemptCountInResponse() const override { return include_attempt_count_in_response_; }
271 183 : bool includeIsTimeoutRetryHeader() const override { return include_is_timeout_retry_header_; }
272 1617 : const std::vector<ShadowPolicyPtr>& shadowPolicies() const { return shadow_policies_; }
273 1684 : RetryPolicyConstOptRef retryPolicy() const {
274 1684 : if (retry_policy_ != nullptr) {
275 26 : return *retry_policy_;
276 26 : }
277 1658 : return absl::nullopt;
278 1684 : }
279 1684 : HedgePolicyConstOptRef hedgePolicy() const {
280 1684 : if (hedge_policy_ != nullptr) {
281 18 : return *hedge_policy_;
282 18 : }
283 1666 : return absl::nullopt;
284 1684 : }
285 1644 : uint32_t retryShadowBufferLimit() const override { return retry_shadow_buffer_limit_; }
286 :
287 : void traversePerFilterConfig(
288 : const std::string& filter_name,
289 : std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const override;
290 : const envoy::config::core::v3::Metadata& metadata() const override;
291 : const Envoy::Config::TypedMetadata& typedMetadata() const override;
292 :
293 : private:
294 : struct StatNameProvider {
295 : StatNameProvider(absl::string_view name, Stats::SymbolTable& symbol_table)
296 0 : : stat_name_storage_(name, symbol_table) {}
297 : Stats::StatNameManagedStorage stat_name_storage_;
298 : };
299 :
300 : struct VirtualClusterBase : public VirtualCluster {
301 : public:
302 : VirtualClusterBase(const absl::optional<std::string>& name, Stats::StatName stat_name,
303 : Stats::ScopeSharedPtr&& scope, const VirtualClusterStatNames& stat_names)
304 : : name_(name), stat_name_(stat_name), scope_(std::move(scope)),
305 0 : stats_(generateStats(*scope_, stat_names)) {}
306 :
307 : // Router::VirtualCluster
308 : // name_ and stat_name_ are two different representations for the same string, retained in
309 : // memory to avoid symbol-table locks that would be needed when converting on-the-fly.
310 0 : const absl::optional<std::string>& name() const override { return name_; }
311 0 : Stats::StatName statName() const override { return stat_name_; }
312 0 : VirtualClusterStats& stats() const override { return stats_; }
313 :
314 : private:
315 : const absl::optional<std::string> name_;
316 : const Stats::StatName stat_name_;
317 : Stats::ScopeSharedPtr scope_;
318 : mutable VirtualClusterStats stats_;
319 : };
320 :
321 : struct VirtualClusterEntry : public StatNameProvider, public VirtualClusterBase {
322 : VirtualClusterEntry(const envoy::config::route::v3::VirtualCluster& virtual_cluster,
323 : Stats::Scope& scope, const VirtualClusterStatNames& stat_names);
324 : std::vector<Http::HeaderUtility::HeaderDataPtr> headers_;
325 : };
326 :
327 : struct CatchAllVirtualCluster : public VirtualClusterBase {
328 : CatchAllVirtualCluster(Stats::Scope& scope, const VirtualClusterStatNames& stat_names)
329 : : VirtualClusterBase(absl::nullopt, stat_names.other_,
330 0 : scope.scopeFromStatName(stat_names.other_), stat_names) {}
331 : };
332 :
333 : const Stats::StatNameManagedStorage stat_name_storage_;
334 : Stats::ScopeSharedPtr vcluster_scope_;
335 : std::vector<VirtualClusterEntry> virtual_clusters_;
336 : std::unique_ptr<const RateLimitPolicyImpl> rate_limit_policy_;
337 : std::vector<ShadowPolicyPtr> shadow_policies_;
338 : std::unique_ptr<const CorsPolicyImpl> cors_policy_;
339 : // Keep an copy of the shared pointer to the shared part of the route config. This is needed
340 : // to keep the shared part alive while the virtual host is alive.
341 : const CommonConfigSharedPtr global_route_config_;
342 : HeaderParserPtr request_headers_parser_;
343 : HeaderParserPtr response_headers_parser_;
344 : PerFilterConfigs per_filter_configs_;
345 : std::unique_ptr<envoy::config::route::v3::RetryPolicy> retry_policy_;
346 : std::unique_ptr<envoy::config::route::v3::HedgePolicy> hedge_policy_;
347 : std::unique_ptr<const CatchAllVirtualCluster> virtual_cluster_catch_all_;
348 : RouteMetadataPackPtr metadata_;
349 : // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
350 : uint32_t retry_shadow_buffer_limit_{std::numeric_limits<uint32_t>::max()};
351 : const bool include_attempt_count_in_request_ : 1;
352 : const bool include_attempt_count_in_response_ : 1;
353 : const bool include_is_timeout_retry_header_ : 1;
354 : };
355 :
356 : using CommonVirtualHostSharedPtr = std::shared_ptr<CommonVirtualHostImpl>;
357 :
358 : /**
359 : * Virtual host that holds a collection of routes.
360 : */
361 : class VirtualHostImpl : Logger::Loggable<Logger::Id::router> {
362 : public:
363 : VirtualHostImpl(
364 : const envoy::config::route::v3::VirtualHost& virtual_host,
365 : const CommonConfigSharedPtr& global_route_config,
366 : Server::Configuration::ServerFactoryContext& factory_context, Stats::Scope& scope,
367 : ProtobufMessage::ValidationVisitor& validator,
368 : const absl::optional<Upstream::ClusterManager::ClusterInfoMaps>& validation_clusters);
369 :
370 : RouteConstSharedPtr getRouteFromEntries(const RouteCallback& cb,
371 : const Http::RequestHeaderMap& headers,
372 : const StreamInfo::StreamInfo& stream_info,
373 : uint64_t random_value) const;
374 :
375 : RouteConstSharedPtr
376 : getRouteFromRoutes(const RouteCallback& cb, const Http::RequestHeaderMap& headers,
377 : const StreamInfo::StreamInfo& stream_info, uint64_t random_value,
378 : absl::Span<const RouteEntryImplBaseConstSharedPtr> routes) const;
379 :
380 : private:
381 : enum class SslRequirements : uint8_t { None, ExternalOnly, All };
382 :
383 : static const std::shared_ptr<const SslRedirectRoute> SSL_REDIRECT_ROUTE;
384 :
385 : CommonVirtualHostSharedPtr shared_virtual_host_;
386 :
387 : SslRequirements ssl_requirements_;
388 :
389 : std::vector<RouteEntryImplBaseConstSharedPtr> routes_;
390 : Matcher::MatchTreeSharedPtr<Http::HttpMatchingData> matcher_;
391 : };
392 :
393 : using VirtualHostSharedPtr = std::shared_ptr<VirtualHostImpl>;
394 :
395 : /**
396 : * Implementation of RetryPolicy that reads from the proto route or virtual host config.
397 : */
398 : class RetryPolicyImpl : public RetryPolicy {
399 :
400 : public:
401 : RetryPolicyImpl(const envoy::config::route::v3::RetryPolicy& retry_policy,
402 : ProtobufMessage::ValidationVisitor& validation_visitor,
403 : Upstream::RetryExtensionFactoryContext& factory_context);
404 74 : RetryPolicyImpl() = default;
405 :
406 : // Router::RetryPolicy
407 251 : std::chrono::milliseconds perTryTimeout() const override { return per_try_timeout_; }
408 251 : std::chrono::milliseconds perTryIdleTimeout() const override { return per_try_idle_timeout_; }
409 0 : uint32_t numRetries() const override { return num_retries_; }
410 251 : uint32_t retryOn() const override { return retry_on_; }
411 : std::vector<Upstream::RetryHostPredicateSharedPtr> retryHostPredicates() const override;
412 : Upstream::RetryPrioritySharedPtr retryPriority() const override;
413 : absl::Span<const Upstream::RetryOptionsPredicateConstSharedPtr>
414 0 : retryOptionsPredicates() const override {
415 0 : return retry_options_predicates_;
416 0 : }
417 0 : uint32_t hostSelectionMaxAttempts() const override { return host_selection_attempts_; }
418 0 : const std::vector<uint32_t>& retriableStatusCodes() const override {
419 0 : return retriable_status_codes_;
420 0 : }
421 0 : const std::vector<Http::HeaderMatcherSharedPtr>& retriableHeaders() const override {
422 0 : return retriable_headers_;
423 0 : }
424 0 : const std::vector<Http::HeaderMatcherSharedPtr>& retriableRequestHeaders() const override {
425 0 : return retriable_request_headers_;
426 0 : }
427 0 : absl::optional<std::chrono::milliseconds> baseInterval() const override { return base_interval_; }
428 0 : absl::optional<std::chrono::milliseconds> maxInterval() const override { return max_interval_; }
429 0 : const std::vector<ResetHeaderParserSharedPtr>& resetHeaders() const override {
430 0 : return reset_headers_;
431 0 : }
432 0 : std::chrono::milliseconds resetMaxInterval() const override { return reset_max_interval_; }
433 :
434 : private:
435 : std::chrono::milliseconds per_try_timeout_{0};
436 : std::chrono::milliseconds per_try_idle_timeout_{0};
437 : // We set the number of retries to 1 by default (i.e. when no route or vhost level retry policy is
438 : // set) so that when retries get enabled through the x-envoy-retry-on header we default to 1
439 : // retry.
440 : uint32_t num_retries_{1};
441 : uint32_t retry_on_{};
442 : // Each pair contains the name and config proto to be used to create the RetryHostPredicates
443 : // that should be used when with this policy.
444 : std::vector<std::pair<Upstream::RetryHostPredicateFactory&, ProtobufTypes::MessagePtr>>
445 : retry_host_predicate_configs_;
446 : Upstream::RetryPrioritySharedPtr retry_priority_;
447 : // Name and config proto to use to create the RetryPriority to use with this policy. Default
448 : // initialized when no RetryPriority should be used.
449 : std::pair<Upstream::RetryPriorityFactory*, ProtobufTypes::MessagePtr> retry_priority_config_;
450 : uint32_t host_selection_attempts_{1};
451 : std::vector<uint32_t> retriable_status_codes_;
452 : std::vector<Http::HeaderMatcherSharedPtr> retriable_headers_;
453 : std::vector<Http::HeaderMatcherSharedPtr> retriable_request_headers_;
454 : absl::optional<std::chrono::milliseconds> base_interval_;
455 : absl::optional<std::chrono::milliseconds> max_interval_;
456 : std::vector<ResetHeaderParserSharedPtr> reset_headers_{};
457 : std::chrono::milliseconds reset_max_interval_{300000};
458 : ProtobufMessage::ValidationVisitor* validation_visitor_{};
459 : std::vector<Upstream::RetryOptionsPredicateConstSharedPtr> retry_options_predicates_;
460 : };
461 : using DefaultRetryPolicy = ConstSingleton<RetryPolicyImpl>;
462 :
463 : /**
464 : * Implementation of ShadowPolicy that reads from the proto route config.
465 : */
466 : class ShadowPolicyImpl : public ShadowPolicy {
467 : public:
468 : using RequestMirrorPolicy = envoy::config::route::v3::RouteAction::RequestMirrorPolicy;
469 : explicit ShadowPolicyImpl(const RequestMirrorPolicy& config);
470 :
471 : // Router::ShadowPolicy
472 0 : const std::string& cluster() const override { return cluster_; }
473 0 : const Http::LowerCaseString& clusterHeader() const override { return cluster_header_; }
474 0 : const std::string& runtimeKey() const override { return runtime_key_; }
475 0 : const envoy::type::v3::FractionalPercent& defaultValue() const override { return default_value_; }
476 0 : bool traceSampled() const override { return trace_sampled_; }
477 :
478 : private:
479 : const std::string cluster_;
480 : const Http::LowerCaseString cluster_header_;
481 : std::string runtime_key_;
482 : envoy::type::v3::FractionalPercent default_value_;
483 : bool trace_sampled_;
484 : };
485 :
486 : /**
487 : * Implementation of HedgePolicy that reads from the proto route or virtual host config.
488 : */
489 : class HedgePolicyImpl : public HedgePolicy {
490 :
491 : public:
492 : explicit HedgePolicyImpl(const envoy::config::route::v3::HedgePolicy& hedge_policy);
493 : HedgePolicyImpl();
494 :
495 : // Router::HedgePolicy
496 0 : uint32_t initialRequests() const override { return initial_requests_; }
497 0 : const envoy::type::v3::FractionalPercent& additionalRequestChance() const override {
498 0 : return additional_request_chance_;
499 0 : }
500 183 : bool hedgeOnPerTryTimeout() const override { return hedge_on_per_try_timeout_; }
501 :
502 : private:
503 : const uint32_t initial_requests_;
504 : const envoy::type::v3::FractionalPercent additional_request_chance_;
505 : const bool hedge_on_per_try_timeout_;
506 : };
507 : using DefaultHedgePolicy = ConstSingleton<HedgePolicyImpl>;
508 :
509 : /**
510 : * Implementation of Decorator that reads from the proto route decorator.
511 : */
512 : class DecoratorImpl : public Decorator {
513 : public:
514 : explicit DecoratorImpl(const envoy::config::route::v3::Decorator& decorator);
515 :
516 : // Decorator::apply
517 : void apply(Tracing::Span& span) const override;
518 :
519 : // Decorator::getOperation
520 : const std::string& getOperation() const override;
521 :
522 : // Decorator::getOperation
523 : bool propagate() const override;
524 :
525 : private:
526 : const std::string operation_;
527 : const bool propagate_;
528 : };
529 :
530 : /**
531 : * Implementation of RouteTracing that reads from the proto route tracing.
532 : */
533 : class RouteTracingImpl : public RouteTracing {
534 : public:
535 : explicit RouteTracingImpl(const envoy::config::route::v3::Tracing& tracing);
536 :
537 : // Tracing::getClientSampling
538 : const envoy::type::v3::FractionalPercent& getClientSampling() const override;
539 :
540 : // Tracing::getRandomSampling
541 : const envoy::type::v3::FractionalPercent& getRandomSampling() const override;
542 :
543 : // Tracing::getOverallSampling
544 : const envoy::type::v3::FractionalPercent& getOverallSampling() const override;
545 :
546 : const Tracing::CustomTagMap& getCustomTags() const override;
547 :
548 : private:
549 : envoy::type::v3::FractionalPercent client_sampling_;
550 : envoy::type::v3::FractionalPercent random_sampling_;
551 : envoy::type::v3::FractionalPercent overall_sampling_;
552 : Tracing::CustomTagMap custom_tags_;
553 : };
554 :
555 : /**
556 : * Implementation of InternalRedirectPolicy that reads from the proto
557 : * InternalRedirectPolicy of the RouteAction.
558 : */
559 : class InternalRedirectPolicyImpl : public InternalRedirectPolicy {
560 : public:
561 : // Constructor that enables internal redirect with policy_config controlling the configurable
562 : // behaviors.
563 : InternalRedirectPolicyImpl(const envoy::config::route::v3::InternalRedirectPolicy& policy_config,
564 : ProtobufMessage::ValidationVisitor& validator,
565 : absl::string_view current_route_name);
566 : // Default constructor that disables internal redirect.
567 51 : InternalRedirectPolicyImpl() = default;
568 :
569 737 : bool enabled() const override { return enabled_; }
570 :
571 0 : bool shouldRedirectForResponseCode(const Http::Code& response_code) const override {
572 0 : return redirect_response_codes_.contains(response_code);
573 0 : }
574 :
575 : std::vector<InternalRedirectPredicateSharedPtr> predicates() const override;
576 : const std::vector<Http::LowerCaseString>& responseHeadersToCopy() const override;
577 :
578 0 : uint32_t maxInternalRedirects() const override { return max_internal_redirects_; }
579 :
580 0 : bool isCrossSchemeRedirectAllowed() const override { return allow_cross_scheme_redirect_; }
581 :
582 : private:
583 : absl::flat_hash_set<Http::Code> buildRedirectResponseCodes(
584 : const envoy::config::route::v3::InternalRedirectPolicy& policy_config) const;
585 :
586 : const std::string current_route_name_;
587 : const absl::flat_hash_set<Http::Code> redirect_response_codes_;
588 : std::vector<std::pair<InternalRedirectPredicateFactory*, ProtobufTypes::MessagePtr>>
589 : predicate_factories_;
590 : // Vector of header names (as a lower case string to simplify use
591 : // later on), to copy from the response that triggers the redirect
592 : // into the following request.
593 : std::vector<Http::LowerCaseString> response_headers_to_copy_;
594 : // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
595 : const uint32_t max_internal_redirects_{1};
596 : const bool enabled_{false};
597 : const bool allow_cross_scheme_redirect_{false};
598 : };
599 : using DefaultInternalRedirectPolicy = ConstSingleton<InternalRedirectPolicyImpl>;
600 :
601 : /**
602 : * Base implementation for all route entries.q
603 : */
604 : class RouteEntryImplBase : public RouteEntryAndRoute,
605 : public Matchable,
606 : public DirectResponseEntry,
607 : public PathMatchCriterion,
608 : public std::enable_shared_from_this<RouteEntryImplBase>,
609 : Logger::Loggable<Logger::Id::router> {
610 : public:
611 : /**
612 : * @throw EnvoyException with reason if the route configuration contains any errors
613 : */
614 : RouteEntryImplBase(const CommonVirtualHostSharedPtr& vhost,
615 : const envoy::config::route::v3::Route& route,
616 : Server::Configuration::ServerFactoryContext& factory_context,
617 : ProtobufMessage::ValidationVisitor& validator);
618 :
619 4911 : bool isDirectResponse() const { return direct_response_code_.has_value(); }
620 :
621 400 : bool isRedirect() const {
622 400 : if (!isDirectResponse()) {
623 198 : return false;
624 198 : }
625 202 : if (redirect_config_ == nullptr) {
626 202 : return false;
627 202 : }
628 0 : return !redirect_config_->host_redirect_.empty() || !redirect_config_->path_redirect_.empty() ||
629 0 : !redirect_config_->prefix_rewrite_redirect_.empty() ||
630 0 : redirect_config_->regex_rewrite_redirect_ != nullptr;
631 202 : }
632 :
633 : bool matchRoute(const Http::RequestHeaderMap& headers, const StreamInfo::StreamInfo& stream_info,
634 : uint64_t random_value) const;
635 : void validateClusters(const Upstream::ClusterManager::ClusterInfoMaps& cluster_info_maps) const;
636 :
637 : // Router::RouteEntry
638 : const std::string& clusterName() const override;
639 183 : const RouteStatsContextOptRef routeStatsContext() const override {
640 183 : if (route_stats_context_ != nullptr) {
641 0 : return *route_stats_context_;
642 0 : }
643 183 : return RouteStatsContextOptRef();
644 183 : }
645 0 : Http::Code clusterNotFoundResponseCode() const override {
646 0 : return cluster_not_found_response_code_;
647 0 : }
648 0 : const CorsPolicy* corsPolicy() const override { return cors_policy_.get(); }
649 196 : const HeaderParser& requestHeaderParser() const {
650 196 : if (request_headers_parser_ != nullptr) {
651 3 : return *request_headers_parser_;
652 3 : }
653 193 : return HeaderParser::defaultParser();
654 196 : }
655 335 : const HeaderParser& responseHeaderParser() const {
656 335 : if (response_headers_parser_ != nullptr) {
657 0 : return *response_headers_parser_;
658 0 : }
659 335 : return HeaderParser::defaultParser();
660 335 : }
661 : void finalizeRequestHeaders(Http::RequestHeaderMap& headers,
662 : const StreamInfo::StreamInfo& stream_info,
663 : bool insert_envoy_original_path) const override;
664 : Http::HeaderTransforms requestHeaderTransforms(const StreamInfo::StreamInfo& stream_info,
665 : bool do_formatting = true) const override;
666 : void finalizeResponseHeaders(Http::ResponseHeaderMap& headers,
667 : const StreamInfo::StreamInfo& stream_info) const override;
668 : Http::HeaderTransforms responseHeaderTransforms(const StreamInfo::StreamInfo& stream_info,
669 : bool do_formatting = true) const override;
670 0 : const Http::HashPolicy* hashPolicy() const override { return hash_policy_.get(); }
671 :
672 183 : const HedgePolicy& hedgePolicy() const override {
673 183 : if (hedge_policy_ != nullptr) {
674 0 : return *hedge_policy_;
675 0 : }
676 183 : return DefaultHedgePolicy::get();
677 183 : }
678 :
679 0 : const MetadataMatchCriteria* metadataMatchCriteria() const override {
680 0 : return metadata_match_criteria_.get();
681 0 : }
682 674 : const TlsContextMatchCriteria* tlsContextMatchCriteria() const override {
683 674 : return tls_context_match_criteria_.get();
684 674 : }
685 366 : Upstream::ResourcePriority priority() const override { return priority_; }
686 0 : const RateLimitPolicy& rateLimitPolicy() const override {
687 0 : if (rate_limit_policy_ != nullptr) {
688 0 : return *rate_limit_policy_;
689 0 : }
690 0 : return DefaultRateLimitPolicy::get();
691 0 : }
692 549 : const RetryPolicy& retryPolicy() const override {
693 549 : if (retry_policy_ != nullptr) {
694 0 : return *retry_policy_;
695 0 : }
696 549 : return DefaultRetryPolicy::get();
697 549 : }
698 238 : const InternalRedirectPolicy& internalRedirectPolicy() const override {
699 238 : if (internal_redirect_policy_ != nullptr) {
700 0 : return *internal_redirect_policy_;
701 0 : }
702 238 : return DefaultInternalRedirectPolicy::get();
703 238 : }
704 :
705 0 : const PathMatcherSharedPtr& pathMatcher() const override { return path_matcher_; }
706 0 : const PathRewriterSharedPtr& pathRewriter() const override { return path_rewriter_; }
707 :
708 183 : uint32_t retryShadowBufferLimit() const override { return retry_shadow_buffer_limit_; }
709 756 : const std::vector<ShadowPolicyPtr>& shadowPolicies() const override { return shadow_policies_; }
710 183 : const VirtualCluster* virtualCluster(const Http::HeaderMap& headers) const override {
711 183 : return vhost_->virtualClusterFromEntries(headers);
712 183 : }
713 183 : std::chrono::milliseconds timeout() const override { return timeout_; }
714 183 : bool usingNewTimeouts() const override { return using_new_timeouts_; }
715 :
716 : // `OptionalTimeouts` manages various `optional` values. We pack them in a
717 : // separate data structure for memory efficiency -- avoiding overhead of
718 : // `absl::optional` per variable, and avoiding overhead of storing unset
719 : // timeouts.
720 : enum class OptionalTimeoutNames {
721 : IdleTimeout = 0,
722 : MaxStreamDuration,
723 : GrpcTimeoutHeaderMax,
724 : GrpcTimeoutHeaderOffset,
725 : MaxGrpcTimeout,
726 : GrpcTimeoutOffset
727 : };
728 : using OptionalTimeouts = PackedStruct<std::chrono::milliseconds, 6, OptionalTimeoutNames>;
729 :
730 185 : absl::optional<std::chrono::milliseconds> idleTimeout() const override {
731 185 : return getOptionalTimeout<OptionalTimeoutNames::IdleTimeout>();
732 185 : }
733 185 : absl::optional<std::chrono::milliseconds> maxStreamDuration() const override {
734 185 : return getOptionalTimeout<OptionalTimeoutNames::MaxStreamDuration>();
735 185 : }
736 0 : absl::optional<std::chrono::milliseconds> grpcTimeoutHeaderMax() const override {
737 0 : return getOptionalTimeout<OptionalTimeoutNames::GrpcTimeoutHeaderMax>();
738 0 : }
739 0 : absl::optional<std::chrono::milliseconds> grpcTimeoutHeaderOffset() const override {
740 0 : return getOptionalTimeout<OptionalTimeoutNames::GrpcTimeoutHeaderOffset>();
741 0 : }
742 0 : absl::optional<std::chrono::milliseconds> maxGrpcTimeout() const override {
743 0 : return getOptionalTimeout<OptionalTimeoutNames::MaxGrpcTimeout>();
744 0 : }
745 0 : absl::optional<std::chrono::milliseconds> grpcTimeoutOffset() const override {
746 0 : return getOptionalTimeout<OptionalTimeoutNames::GrpcTimeoutOffset>();
747 0 : }
748 :
749 387 : const VirtualHost& virtualHost() const override { return *vhost_; }
750 134 : bool autoHostRewrite() const override { return auto_host_rewrite_; }
751 0 : bool appendXfh() const override { return append_xfh_; }
752 0 : const std::multimap<std::string, std::string>& opaqueConfig() const override {
753 0 : return opaque_config_;
754 0 : }
755 0 : bool includeVirtualHostRateLimits() const override { return include_vh_rate_limits_; }
756 : const envoy::config::core::v3::Metadata& metadata() const override;
757 : const Envoy::Config::TypedMetadata& typedMetadata() const override;
758 0 : const PathMatchCriterion& pathMatchCriterion() const override { return *this; }
759 183 : bool includeAttemptCountInRequest() const override {
760 183 : return vhost_->includeAttemptCountInRequest();
761 183 : }
762 183 : bool includeAttemptCountInResponse() const override {
763 183 : return vhost_->includeAttemptCountInResponse();
764 183 : }
765 183 : const ConnectConfigOptRef connectConfig() const override {
766 183 : if (connect_config_ != nullptr) {
767 0 : return *connect_config_;
768 0 : }
769 183 : return absl::nullopt;
770 183 : }
771 0 : const UpgradeMap& upgradeMap() const override { return upgrade_map_; }
772 183 : const EarlyDataPolicy& earlyDataPolicy() const override { return *early_data_policy_; }
773 :
774 : // Router::DirectResponseEntry
775 : std::string newUri(const Http::RequestHeaderMap& headers) const override;
776 0 : void rewritePathHeader(Http::RequestHeaderMap&, bool) const override {}
777 606 : Http::Code responseCode() const override { return direct_response_code_.value(); }
778 202 : const std::string& responseBody() const override { return direct_response_body_; }
779 :
780 : // Router::Route
781 : const DirectResponseEntry* directResponseEntry() const override;
782 : const RouteEntry* routeEntry() const override;
783 0 : const Decorator* decorator() const override { return decorator_.get(); }
784 0 : const RouteTracing* tracingConfig() const override { return route_tracing_.get(); }
785 : absl::optional<bool> filterDisabled(absl::string_view config_name) const override;
786 : const RouteSpecificFilterConfig*
787 0 : mostSpecificPerFilterConfig(const std::string& name) const override {
788 0 : auto* config = per_filter_configs_.get(name);
789 0 : return config ? config : vhost_->mostSpecificPerFilterConfig(name);
790 0 : }
791 : void traversePerFilterConfig(
792 : const std::string& filter_name,
793 : std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const override;
794 0 : const std::string& routeName() const override { return route_name_; }
795 :
796 : // Sanitizes the |path| before passing it to PathMatcher, if configured, this method makes the
797 : // path matching to ignore the path-parameters.
798 : absl::string_view sanitizePathBeforePathMatching(const absl::string_view path) const;
799 :
800 : class DynamicRouteEntry : public RouteEntryAndRoute {
801 : public:
802 : DynamicRouteEntry(const RouteEntryAndRoute* parent, RouteConstSharedPtr owner,
803 : const std::string& name)
804 209 : : parent_(parent), owner_(std::move(owner)), cluster_name_(name) {}
805 :
806 : // Router::RouteEntry
807 262 : const std::string& clusterName() const override { return cluster_name_; }
808 0 : Http::Code clusterNotFoundResponseCode() const override {
809 0 : return parent_->clusterNotFoundResponseCode();
810 0 : }
811 :
812 : absl::optional<std::string>
813 0 : currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers) const override {
814 0 : return parent_->currentUrlPathAfterRewrite(headers);
815 0 : }
816 : void finalizeRequestHeaders(Http::RequestHeaderMap& headers,
817 : const StreamInfo::StreamInfo& stream_info,
818 13 : bool insert_envoy_original_path) const override {
819 13 : return parent_->finalizeRequestHeaders(headers, stream_info, insert_envoy_original_path);
820 13 : }
821 : Http::HeaderTransforms requestHeaderTransforms(const StreamInfo::StreamInfo& stream_info,
822 0 : bool do_formatting = true) const override {
823 0 : return parent_->requestHeaderTransforms(stream_info, do_formatting);
824 0 : }
825 : void finalizeResponseHeaders(Http::ResponseHeaderMap& headers,
826 0 : const StreamInfo::StreamInfo& stream_info) const override {
827 0 : return parent_->finalizeResponseHeaders(headers, stream_info);
828 0 : }
829 : Http::HeaderTransforms responseHeaderTransforms(const StreamInfo::StreamInfo& stream_info,
830 0 : bool do_formatting = true) const override {
831 0 : return parent_->responseHeaderTransforms(stream_info, do_formatting);
832 0 : }
833 :
834 0 : const CorsPolicy* corsPolicy() const override { return parent_->corsPolicy(); }
835 0 : const Http::HashPolicy* hashPolicy() const override { return parent_->hashPolicy(); }
836 0 : const HedgePolicy& hedgePolicy() const override { return parent_->hedgePolicy(); }
837 0 : Upstream::ResourcePriority priority() const override { return parent_->priority(); }
838 0 : const RateLimitPolicy& rateLimitPolicy() const override { return parent_->rateLimitPolicy(); }
839 0 : const RetryPolicy& retryPolicy() const override { return parent_->retryPolicy(); }
840 0 : const InternalRedirectPolicy& internalRedirectPolicy() const override {
841 0 : return parent_->internalRedirectPolicy();
842 0 : }
843 0 : const PathMatcherSharedPtr& pathMatcher() const override { return parent_->pathMatcher(); }
844 0 : const PathRewriterSharedPtr& pathRewriter() const override { return parent_->pathRewriter(); }
845 0 : uint32_t retryShadowBufferLimit() const override { return parent_->retryShadowBufferLimit(); }
846 0 : const std::vector<ShadowPolicyPtr>& shadowPolicies() const override {
847 0 : return parent_->shadowPolicies();
848 0 : }
849 0 : std::chrono::milliseconds timeout() const override { return parent_->timeout(); }
850 0 : absl::optional<std::chrono::milliseconds> idleTimeout() const override {
851 0 : return parent_->idleTimeout();
852 0 : }
853 0 : bool usingNewTimeouts() const override { return parent_->usingNewTimeouts(); }
854 0 : absl::optional<std::chrono::milliseconds> maxStreamDuration() const override {
855 0 : return parent_->maxStreamDuration();
856 0 : }
857 0 : absl::optional<std::chrono::milliseconds> grpcTimeoutHeaderMax() const override {
858 0 : return parent_->grpcTimeoutHeaderMax();
859 0 : }
860 0 : absl::optional<std::chrono::milliseconds> grpcTimeoutHeaderOffset() const override {
861 0 : return parent_->grpcTimeoutHeaderOffset();
862 0 : }
863 0 : absl::optional<std::chrono::milliseconds> maxGrpcTimeout() const override {
864 0 : return parent_->maxGrpcTimeout();
865 0 : }
866 0 : absl::optional<std::chrono::milliseconds> grpcTimeoutOffset() const override {
867 0 : return parent_->grpcTimeoutOffset();
868 0 : }
869 0 : const MetadataMatchCriteria* metadataMatchCriteria() const override {
870 0 : return parent_->metadataMatchCriteria();
871 0 : }
872 0 : const TlsContextMatchCriteria* tlsContextMatchCriteria() const override {
873 0 : return parent_->tlsContextMatchCriteria();
874 0 : }
875 :
876 0 : const VirtualCluster* virtualCluster(const Http::HeaderMap& headers) const override {
877 0 : return parent_->virtualCluster(headers);
878 0 : }
879 :
880 0 : const std::multimap<std::string, std::string>& opaqueConfig() const override {
881 0 : return parent_->opaqueConfig();
882 0 : }
883 :
884 0 : const VirtualHost& virtualHost() const override { return parent_->virtualHost(); }
885 0 : bool autoHostRewrite() const override { return parent_->autoHostRewrite(); }
886 0 : bool appendXfh() const override { return parent_->appendXfh(); }
887 0 : bool includeVirtualHostRateLimits() const override {
888 0 : return parent_->includeVirtualHostRateLimits();
889 0 : }
890 0 : const envoy::config::core::v3::Metadata& metadata() const override {
891 0 : return parent_->metadata();
892 0 : }
893 0 : const Envoy::Config::TypedMetadata& typedMetadata() const override {
894 0 : return parent_->typedMetadata();
895 0 : }
896 0 : const PathMatchCriterion& pathMatchCriterion() const override {
897 0 : return parent_->pathMatchCriterion();
898 0 : }
899 :
900 0 : bool includeAttemptCountInRequest() const override {
901 0 : return parent_->includeAttemptCountInRequest();
902 0 : }
903 0 : bool includeAttemptCountInResponse() const override {
904 0 : return parent_->includeAttemptCountInResponse();
905 0 : }
906 0 : const ConnectConfigOptRef connectConfig() const override { return parent_->connectConfig(); }
907 0 : const RouteStatsContextOptRef routeStatsContext() const override {
908 0 : return parent_->routeStatsContext();
909 0 : }
910 0 : const UpgradeMap& upgradeMap() const override { return parent_->upgradeMap(); }
911 0 : const EarlyDataPolicy& earlyDataPolicy() const override { return parent_->earlyDataPolicy(); }
912 :
913 : // Router::Route
914 0 : const DirectResponseEntry* directResponseEntry() const override { return nullptr; }
915 22 : const RouteEntry* routeEntry() const override { return this; }
916 0 : const Decorator* decorator() const override { return parent_->decorator(); }
917 0 : const RouteTracing* tracingConfig() const override { return parent_->tracingConfig(); }
918 0 : absl::optional<bool> filterDisabled(absl::string_view config_name) const override {
919 0 : return parent_->filterDisabled(config_name);
920 0 : }
921 : const RouteSpecificFilterConfig*
922 0 : mostSpecificPerFilterConfig(const std::string& name) const override {
923 0 : return parent_->mostSpecificPerFilterConfig(name);
924 0 : }
925 : void traversePerFilterConfig(
926 : const std::string& filter_name,
927 0 : std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const override {
928 0 : parent_->traversePerFilterConfig(filter_name, cb);
929 0 : };
930 0 : const std::string& routeName() const override { return parent_->routeName(); }
931 :
932 : private:
933 : const RouteEntryAndRoute* parent_;
934 :
935 : // If a DynamicRouteEntry instance is created and returned to the caller directly, then keep an
936 : // copy of the shared pointer to the parent Route (RouteEntryImplBase) to ensure the parent
937 : // is not destroyed before this entry.
938 : //
939 : // This should be nullptr if the DynamicRouteEntry is part of the parent (RouteEntryImplBase) to
940 : // avoid possible circular reference. For example, the WeightedClusterEntry (derived from
941 : // DynamicRouteEntry) will be member of the RouteEntryImplBase, so the owner_ should be nullptr.
942 : const RouteConstSharedPtr owner_;
943 : const std::string cluster_name_;
944 : };
945 :
946 : /**
947 : * Route entry implementation for weighted clusters. The RouteEntryImplBase object holds
948 : * one or more weighted cluster objects, where each object has a back pointer to the parent
949 : * RouteEntryImplBase object. Almost all functions in this class forward calls back to the
950 : * parent, with the exception of clusterName, routeEntry, and metadataMatchCriteria.
951 : */
952 : class WeightedClusterEntry : public DynamicRouteEntry {
953 : public:
954 : WeightedClusterEntry(const RouteEntryImplBase* parent, const std::string& rutime_key,
955 : Server::Configuration::ServerFactoryContext& factory_context,
956 : ProtobufMessage::ValidationVisitor& validator,
957 : const envoy::config::route::v3::WeightedCluster::ClusterWeight& cluster);
958 :
959 200 : uint64_t clusterWeight() const {
960 200 : return loader_.snapshot().getInteger(runtime_key_, cluster_weight_);
961 200 : }
962 :
963 0 : const MetadataMatchCriteria* metadataMatchCriteria() const override {
964 0 : if (cluster_metadata_match_criteria_) {
965 0 : return cluster_metadata_match_criteria_.get();
966 0 : }
967 0 : return DynamicRouteEntry::metadataMatchCriteria();
968 0 : }
969 :
970 2 : const HeaderParser& requestHeaderParser() const {
971 2 : if (request_headers_parser_ != nullptr) {
972 2 : return *request_headers_parser_;
973 2 : }
974 0 : return HeaderParser::defaultParser();
975 2 : }
976 0 : const HeaderParser& responseHeaderParser() const {
977 0 : if (response_headers_parser_ != nullptr) {
978 0 : return *response_headers_parser_;
979 0 : }
980 0 : return HeaderParser::defaultParser();
981 0 : }
982 :
983 : void finalizeRequestHeaders(Http::RequestHeaderMap& headers,
984 : const StreamInfo::StreamInfo& stream_info,
985 2 : bool insert_envoy_original_path) const override {
986 2 : requestHeaderParser().evaluateHeaders(headers, stream_info);
987 2 : if (!host_rewrite_.empty()) {
988 2 : headers.setHost(host_rewrite_);
989 2 : }
990 2 : DynamicRouteEntry::finalizeRequestHeaders(headers, stream_info, insert_envoy_original_path);
991 2 : }
992 : Http::HeaderTransforms requestHeaderTransforms(const StreamInfo::StreamInfo& stream_info,
993 : bool do_formatting = true) const override;
994 : void finalizeResponseHeaders(Http::ResponseHeaderMap& headers,
995 0 : const StreamInfo::StreamInfo& stream_info) const override {
996 0 : const Http::RequestHeaderMap& request_headers =
997 0 : stream_info.getRequestHeaders() == nullptr
998 0 : ? *Http::StaticEmptyHeaders::get().request_headers
999 0 : : *stream_info.getRequestHeaders();
1000 0 : responseHeaderParser().evaluateHeaders(headers, {&request_headers, &headers}, stream_info);
1001 0 : DynamicRouteEntry::finalizeResponseHeaders(headers, stream_info);
1002 0 : }
1003 : Http::HeaderTransforms responseHeaderTransforms(const StreamInfo::StreamInfo& stream_info,
1004 : bool do_formatting = true) const override;
1005 :
1006 0 : absl::optional<bool> filterDisabled(absl::string_view config_name) const override {
1007 0 : absl::optional<bool> result = per_filter_configs_.disabled(config_name);
1008 0 : if (result.has_value()) {
1009 0 : return result.value();
1010 0 : }
1011 0 : return DynamicRouteEntry::filterDisabled(config_name);
1012 0 : }
1013 : const RouteSpecificFilterConfig*
1014 0 : mostSpecificPerFilterConfig(const std::string& name) const override {
1015 0 : auto* config = per_filter_configs_.get(name);
1016 0 : return config ? config : DynamicRouteEntry::mostSpecificPerFilterConfig(name);
1017 0 : }
1018 :
1019 : void traversePerFilterConfig(
1020 : const std::string& filter_name,
1021 : std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const override;
1022 :
1023 16 : const Http::LowerCaseString& clusterHeaderName() const { return cluster_header_name_; }
1024 :
1025 : private:
1026 : const std::string runtime_key_;
1027 : Runtime::Loader& loader_;
1028 : const uint64_t cluster_weight_;
1029 : MetadataMatchCriteriaConstPtr cluster_metadata_match_criteria_;
1030 : HeaderParserPtr request_headers_parser_;
1031 : HeaderParserPtr response_headers_parser_;
1032 : PerFilterConfigs per_filter_configs_;
1033 : const std::string host_rewrite_;
1034 : const Http::LowerCaseString cluster_header_name_;
1035 : };
1036 :
1037 : using WeightedClusterEntrySharedPtr = std::shared_ptr<WeightedClusterEntry>;
1038 : // Container for route config elements that pertain to weighted clusters.
1039 : // We keep them in a separate data structure to avoid memory overhead for the routes that do not
1040 : // use weighted clusters.
1041 : struct WeightedClustersConfig {
1042 : WeightedClustersConfig(const std::vector<WeightedClusterEntrySharedPtr>&& weighted_clusters,
1043 : uint64_t total_cluster_weight,
1044 : const std::string& random_value_header_name)
1045 : : weighted_clusters_(std::move(weighted_clusters)),
1046 : total_cluster_weight_(total_cluster_weight),
1047 86 : random_value_header_name_(random_value_header_name) {}
1048 : const std::vector<WeightedClusterEntrySharedPtr> weighted_clusters_;
1049 : const uint64_t total_cluster_weight_;
1050 : const std::string random_value_header_name_;
1051 : };
1052 :
1053 : protected:
1054 : const std::string prefix_rewrite_;
1055 : Regex::CompiledMatcherPtr regex_rewrite_;
1056 : const PathMatcherSharedPtr path_matcher_;
1057 : const PathRewriterSharedPtr path_rewriter_;
1058 : std::string regex_rewrite_substitution_;
1059 : const std::string host_rewrite_;
1060 : std::unique_ptr<ConnectConfig> connect_config_;
1061 :
1062 1466 : bool case_sensitive() const { return case_sensitive_; }
1063 : RouteConstSharedPtr clusterEntry(const Http::RequestHeaderMap& headers,
1064 : uint64_t random_value) const;
1065 :
1066 : /**
1067 : * Returns the correct path rewrite string for this route.
1068 : *
1069 : * The provided container may be used to store memory backing the return value
1070 : * therefore it must outlive any use of the return value.
1071 : */
1072 : const std::string& getPathRewrite(const Http::RequestHeaderMap& headers,
1073 : absl::optional<std::string>& container) const;
1074 :
1075 : void finalizePathHeader(Http::RequestHeaderMap& headers, absl::string_view matched_path,
1076 : bool insert_envoy_original_path) const;
1077 :
1078 : absl::optional<std::string>
1079 : currentUrlPathAfterRewriteWithMatchedPath(const Http::RequestHeaderMap& headers,
1080 : absl::string_view matched_path) const;
1081 :
1082 : private:
1083 : struct RuntimeData {
1084 : std::string fractional_runtime_key_{};
1085 : envoy::type::v3::FractionalPercent fractional_runtime_default_{};
1086 : };
1087 :
1088 : /**
1089 : * Returns a vector of request header parsers which applied or will apply header transformations
1090 : * to the request in this route.
1091 : * @param specificity_ascend specifies whether the returned parsers will be sorted from least
1092 : * specific to most specific (global connection manager level header parser, virtual host
1093 : * level header parser and finally route-level parser.) or the reverse.
1094 : * @return a vector of request header parsers.
1095 : */
1096 : absl::InlinedVector<const HeaderParser*, 3>
1097 : getRequestHeaderParsers(bool specificity_ascend) const;
1098 :
1099 : /**
1100 : * Returns a vector of response header parsers which applied or will apply header transformations
1101 : * to the response in this route.
1102 : * @param specificity_ascend specifies whether the returned parsers will be sorted from least
1103 : * specific to most specific (global connection manager level header parser, virtual host
1104 : * level header parser and finally route-level parser.) or the reverse.
1105 : * @return a vector of request header parsers.
1106 : */
1107 : absl::InlinedVector<const HeaderParser*, 3>
1108 : getResponseHeaderParsers(bool specificity_ascend) const;
1109 :
1110 : std::unique_ptr<const RuntimeData>
1111 : loadRuntimeData(const envoy::config::route::v3::RouteMatch& route);
1112 :
1113 : static std::multimap<std::string, std::string>
1114 : parseOpaqueConfig(const envoy::config::route::v3::Route& route);
1115 :
1116 : static DecoratorConstPtr parseDecorator(const envoy::config::route::v3::Route& route);
1117 :
1118 : static RouteTracingConstPtr parseRouteTracing(const envoy::config::route::v3::Route& route);
1119 :
1120 : bool evaluateRuntimeMatch(const uint64_t random_value) const;
1121 :
1122 : bool evaluateTlsContextMatch(const StreamInfo::StreamInfo& stream_info) const;
1123 :
1124 : std::unique_ptr<HedgePolicyImpl>
1125 : buildHedgePolicy(HedgePolicyConstOptRef vhost_hedge_policy,
1126 : const envoy::config::route::v3::RouteAction& route_config) const;
1127 :
1128 : std::unique_ptr<RetryPolicyImpl>
1129 : buildRetryPolicy(RetryPolicyConstOptRef vhost_retry_policy,
1130 : const envoy::config::route::v3::RouteAction& route_config,
1131 : ProtobufMessage::ValidationVisitor& validation_visitor,
1132 : Server::Configuration::ServerFactoryContext& factory_context) const;
1133 :
1134 : std::unique_ptr<InternalRedirectPolicyImpl>
1135 : buildInternalRedirectPolicy(const envoy::config::route::v3::RouteAction& route_config,
1136 : ProtobufMessage::ValidationVisitor& validator,
1137 : absl::string_view current_route_name) const;
1138 :
1139 : OptionalTimeouts buildOptionalTimeouts(const envoy::config::route::v3::RouteAction& route) const;
1140 : template <OptionalTimeoutNames timeout_name>
1141 370 : absl::optional<std::chrono::milliseconds> getOptionalTimeout() const {
1142 370 : const auto timeout = optional_timeouts_.get<timeout_name>();
1143 370 : if (timeout.has_value()) {
1144 0 : return *timeout;
1145 0 : }
1146 370 : return absl::nullopt;
1147 370 : }
1148 :
1149 : PathMatcherSharedPtr buildPathMatcher(envoy::config::route::v3::Route route,
1150 : ProtobufMessage::ValidationVisitor& validator) const;
1151 :
1152 : PathRewriterSharedPtr buildPathRewriter(envoy::config::route::v3::Route route,
1153 : ProtobufMessage::ValidationVisitor& validator) const;
1154 :
1155 : RouteConstSharedPtr
1156 : pickClusterViaClusterHeader(const Http::LowerCaseString& cluster_header_name,
1157 : const Http::HeaderMap& headers,
1158 : const RouteEntryAndRoute* route_selector_override) const;
1159 :
1160 : RouteConstSharedPtr pickWeightedCluster(const Http::HeaderMap& headers, uint64_t random_value,
1161 : bool ignore_overflow) const;
1162 :
1163 : // Default timeout is 15s if nothing is specified in the route config.
1164 : static const uint64_t DEFAULT_ROUTE_TIMEOUT_MS = 15000;
1165 :
1166 : std::unique_ptr<const CorsPolicyImpl> cors_policy_;
1167 : // Keep an copy of the shared pointer to the shared part of the virtual host. This is needed
1168 : // to keep the shared part alive while the route is alive.
1169 : const CommonVirtualHostSharedPtr vhost_;
1170 : const absl::optional<Http::LowerCaseString> auto_host_rewrite_header_;
1171 : const Regex::CompiledMatcherPtr host_rewrite_path_regex_;
1172 : const std::string host_rewrite_path_regex_substitution_;
1173 : const std::string cluster_name_;
1174 : RouteStatsContextPtr route_stats_context_;
1175 : const Http::LowerCaseString cluster_header_name_;
1176 : ClusterSpecifierPluginSharedPtr cluster_specifier_plugin_;
1177 : const std::chrono::milliseconds timeout_;
1178 : const OptionalTimeouts optional_timeouts_;
1179 : Runtime::Loader& loader_;
1180 : std::unique_ptr<const RuntimeData> runtime_;
1181 : std::unique_ptr<const ::Envoy::Http::Utility::RedirectConfig> redirect_config_;
1182 : std::unique_ptr<const HedgePolicyImpl> hedge_policy_;
1183 : std::unique_ptr<const RetryPolicyImpl> retry_policy_;
1184 : std::unique_ptr<const InternalRedirectPolicyImpl> internal_redirect_policy_;
1185 : std::unique_ptr<const RateLimitPolicyImpl> rate_limit_policy_;
1186 : std::vector<ShadowPolicyPtr> shadow_policies_;
1187 : std::vector<Http::HeaderUtility::HeaderDataPtr> config_headers_;
1188 : std::vector<ConfigUtility::QueryParameterMatcherPtr> config_query_parameters_;
1189 : std::unique_ptr<const WeightedClustersConfig> weighted_clusters_config_;
1190 :
1191 : UpgradeMap upgrade_map_;
1192 : std::unique_ptr<const Http::HashPolicyImpl> hash_policy_;
1193 : MetadataMatchCriteriaConstPtr metadata_match_criteria_;
1194 : TlsContextMatchCriteriaConstPtr tls_context_match_criteria_;
1195 : HeaderParserPtr request_headers_parser_;
1196 : HeaderParserPtr response_headers_parser_;
1197 : RouteMetadataPackPtr metadata_;
1198 : const std::vector<Envoy::Matchers::MetadataMatcher> dynamic_metadata_;
1199 :
1200 : // TODO(danielhochman): refactor multimap into unordered_map since JSON is unordered map.
1201 : const std::multimap<std::string, std::string> opaque_config_;
1202 :
1203 : const DecoratorConstPtr decorator_;
1204 : const RouteTracingConstPtr route_tracing_;
1205 : std::string direct_response_body_;
1206 : PerFilterConfigs per_filter_configs_;
1207 : const std::string route_name_;
1208 : TimeSource& time_source_;
1209 : EarlyDataPolicyPtr early_data_policy_;
1210 :
1211 : // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
1212 : uint32_t retry_shadow_buffer_limit_{std::numeric_limits<uint32_t>::max()};
1213 : const absl::optional<Http::Code> direct_response_code_;
1214 : const Http::Code cluster_not_found_response_code_;
1215 : const Upstream::ResourcePriority priority_;
1216 : const bool auto_host_rewrite_ : 1;
1217 : const bool append_xfh_ : 1;
1218 : const bool using_new_timeouts_ : 1;
1219 : const bool match_grpc_ : 1;
1220 : const bool case_sensitive_ : 1;
1221 : bool include_vh_rate_limits_ : 1;
1222 : };
1223 :
1224 : /**
1225 : * Route entry implementation for uri template match based routing.
1226 : */
1227 : class UriTemplateMatcherRouteEntryImpl : public RouteEntryImplBase {
1228 : public:
1229 : UriTemplateMatcherRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
1230 : const envoy::config::route::v3::Route& route,
1231 : Server::Configuration::ServerFactoryContext& factory_context,
1232 : ProtobufMessage::ValidationVisitor& validator);
1233 :
1234 : // Router::PathMatchCriterion
1235 0 : const std::string& matcher() const override { return uri_template_; }
1236 0 : PathMatchType matchType() const override { return PathMatchType::Template; }
1237 :
1238 : // Router::Matchable
1239 : RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
1240 : const StreamInfo::StreamInfo& stream_info,
1241 : uint64_t random_value) const override;
1242 :
1243 : // Router::DirectResponseEntry
1244 : void rewritePathHeader(Http::RequestHeaderMap& headers,
1245 : bool insert_envoy_original_path) const override;
1246 :
1247 : // Router::RouteEntry
1248 : absl::optional<std::string>
1249 : currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers) const override;
1250 :
1251 : private:
1252 : const std::string uri_template_;
1253 : };
1254 :
1255 : /**
1256 : * Route entry implementation for prefix path match routing.
1257 : */
1258 : class PrefixRouteEntryImpl : public RouteEntryImplBase {
1259 : public:
1260 : PrefixRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
1261 : const envoy::config::route::v3::Route& route,
1262 : Server::Configuration::ServerFactoryContext& factory_context,
1263 : ProtobufMessage::ValidationVisitor& validator);
1264 :
1265 : // Router::PathMatchCriterion
1266 203 : const std::string& matcher() const override {
1267 203 : return path_matcher_ != nullptr ? path_matcher_->matcher().matcher().prefix() : EMPTY_STRING;
1268 203 : }
1269 0 : PathMatchType matchType() const override { return PathMatchType::Prefix; }
1270 :
1271 : // Router::Matchable
1272 : RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
1273 : const StreamInfo::StreamInfo& stream_info,
1274 : uint64_t random_value) const override;
1275 :
1276 : // Router::DirectResponseEntry
1277 : void rewritePathHeader(Http::RequestHeaderMap& headers,
1278 : bool insert_envoy_original_path) const override;
1279 :
1280 : // Router::RouteEntry
1281 : absl::optional<std::string>
1282 : currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers) const override;
1283 :
1284 : private:
1285 : const Matchers::PathMatcherConstSharedPtr path_matcher_;
1286 : };
1287 :
1288 : /**
1289 : * Route entry implementation for exact path match routing.
1290 : */
1291 : class PathRouteEntryImpl : public RouteEntryImplBase {
1292 : public:
1293 : PathRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
1294 : const envoy::config::route::v3::Route& route,
1295 : Server::Configuration::ServerFactoryContext& factory_context,
1296 : ProtobufMessage::ValidationVisitor& validator);
1297 :
1298 : // Router::PathMatchCriterion
1299 0 : const std::string& matcher() const override {
1300 0 : return path_matcher_ != nullptr ? path_matcher_->matcher().matcher().exact() : EMPTY_STRING;
1301 0 : }
1302 0 : PathMatchType matchType() const override { return PathMatchType::Exact; }
1303 :
1304 : // Router::Matchable
1305 : RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
1306 : const StreamInfo::StreamInfo& stream_info,
1307 : uint64_t random_value) const override;
1308 :
1309 : // Router::DirectResponseEntry
1310 : void rewritePathHeader(Http::RequestHeaderMap& headers,
1311 : bool insert_envoy_original_path) const override;
1312 :
1313 : // Router::RouteEntry
1314 : absl::optional<std::string>
1315 : currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers) const override;
1316 :
1317 : private:
1318 : const Matchers::PathMatcherConstSharedPtr path_matcher_;
1319 : };
1320 :
1321 : /**
1322 : * Route entry implementation for regular expression match routing.
1323 : */
1324 : class RegexRouteEntryImpl : public RouteEntryImplBase {
1325 : public:
1326 : RegexRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
1327 : const envoy::config::route::v3::Route& route,
1328 : Server::Configuration::ServerFactoryContext& factory_context,
1329 : ProtobufMessage::ValidationVisitor& validator);
1330 :
1331 : // Router::PathMatchCriterion
1332 0 : const std::string& matcher() const override {
1333 0 : return path_matcher_ != nullptr ? path_matcher_->matcher().matcher().safe_regex().regex()
1334 0 : : EMPTY_STRING;
1335 0 : }
1336 0 : PathMatchType matchType() const override { return PathMatchType::Regex; }
1337 :
1338 : // Router::Matchable
1339 : RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
1340 : const StreamInfo::StreamInfo& stream_info,
1341 : uint64_t random_value) const override;
1342 :
1343 : // Router::DirectResponseEntry
1344 : void rewritePathHeader(Http::RequestHeaderMap& headers,
1345 : bool insert_envoy_original_path) const override;
1346 :
1347 : // Router::RouteEntry
1348 : absl::optional<std::string>
1349 : currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers) const override;
1350 :
1351 : private:
1352 : const Matchers::PathMatcherConstSharedPtr path_matcher_;
1353 : };
1354 :
1355 : /**
1356 : * Route entry implementation for CONNECT requests.
1357 : */
1358 : class ConnectRouteEntryImpl : public RouteEntryImplBase {
1359 : public:
1360 : ConnectRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
1361 : const envoy::config::route::v3::Route& route,
1362 : Server::Configuration::ServerFactoryContext& factory_context,
1363 : ProtobufMessage::ValidationVisitor& validator);
1364 :
1365 : // Router::PathMatchCriterion
1366 0 : const std::string& matcher() const override { return EMPTY_STRING; }
1367 0 : PathMatchType matchType() const override { return PathMatchType::None; }
1368 :
1369 : // Router::Matchable
1370 : RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
1371 : const StreamInfo::StreamInfo& stream_info,
1372 : uint64_t random_value) const override;
1373 :
1374 : // Router::DirectResponseEntry
1375 : void rewritePathHeader(Http::RequestHeaderMap&, bool) const override;
1376 :
1377 : // Router::RouteEntry
1378 : absl::optional<std::string>
1379 : currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers) const override;
1380 :
1381 0 : bool supportsPathlessHeaders() const override { return true; }
1382 : };
1383 :
1384 : /**
1385 : * Route entry implementation for path separated prefix match routing.
1386 : */
1387 : class PathSeparatedPrefixRouteEntryImpl : public RouteEntryImplBase {
1388 : public:
1389 : PathSeparatedPrefixRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
1390 : const envoy::config::route::v3::Route& route,
1391 : Server::Configuration::ServerFactoryContext& factory_context,
1392 : ProtobufMessage::ValidationVisitor& validator);
1393 :
1394 : // Router::PathMatchCriterion
1395 0 : const std::string& matcher() const override {
1396 0 : return path_matcher_ != nullptr ? path_matcher_->matcher().matcher().prefix() : EMPTY_STRING;
1397 0 : }
1398 0 : PathMatchType matchType() const override { return PathMatchType::PathSeparatedPrefix; }
1399 :
1400 : // Router::Matchable
1401 : RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
1402 : const StreamInfo::StreamInfo& stream_info,
1403 : uint64_t random_value) const override;
1404 :
1405 : // Router::DirectResponseEntry
1406 : void rewritePathHeader(Http::RequestHeaderMap& headers,
1407 : bool insert_envoy_original_path) const override;
1408 :
1409 : // Router::RouteEntry
1410 : absl::optional<std::string>
1411 : currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers) const override;
1412 :
1413 : private:
1414 : const Matchers::PathMatcherConstSharedPtr path_matcher_;
1415 : };
1416 :
1417 : // Contextual information used to construct the route actions for a match tree.
1418 : struct RouteActionContext {
1419 : const CommonVirtualHostSharedPtr& vhost;
1420 : Server::Configuration::ServerFactoryContext& factory_context;
1421 : };
1422 :
1423 : // Action used with the matching tree to specify route to use for an incoming stream.
1424 : class RouteMatchAction : public Matcher::ActionBase<envoy::config::route::v3::Route> {
1425 : public:
1426 2 : explicit RouteMatchAction(RouteEntryImplBaseConstSharedPtr route) : route_(std::move(route)) {}
1427 :
1428 2 : RouteEntryImplBaseConstSharedPtr route() const { return route_; }
1429 :
1430 : private:
1431 : const RouteEntryImplBaseConstSharedPtr route_;
1432 : };
1433 :
1434 : // Registered factory for RouteMatchAction.
1435 : class RouteMatchActionFactory : public Matcher::ActionFactory<RouteActionContext> {
1436 : public:
1437 : Matcher::ActionFactoryCb
1438 : createActionFactoryCb(const Protobuf::Message& config, RouteActionContext& context,
1439 : ProtobufMessage::ValidationVisitor& validation_visitor) override;
1440 190 : std::string name() const override { return "route"; }
1441 16 : ProtobufTypes::MessagePtr createEmptyConfigProto() override {
1442 16 : return std::make_unique<envoy::config::route::v3::Route>();
1443 16 : }
1444 : };
1445 :
1446 : DECLARE_FACTORY(RouteMatchActionFactory);
1447 :
1448 : // Similar to RouteMatchAction, but accepts v3::RouteList instead of v3::Route.
1449 : class RouteListMatchAction : public Matcher::ActionBase<envoy::config::route::v3::RouteList> {
1450 : public:
1451 : explicit RouteListMatchAction(std::vector<RouteEntryImplBaseConstSharedPtr> routes)
1452 0 : : routes_(std::move(routes)) {}
1453 :
1454 0 : const std::vector<RouteEntryImplBaseConstSharedPtr>& routes() const { return routes_; }
1455 :
1456 : private:
1457 : const std::vector<RouteEntryImplBaseConstSharedPtr> routes_;
1458 : };
1459 :
1460 : // Registered factory for RouteListMatchAction.
1461 : class RouteListMatchActionFactory : public Matcher::ActionFactory<RouteActionContext> {
1462 : public:
1463 : Matcher::ActionFactoryCb
1464 : createActionFactoryCb(const Protobuf::Message& config, RouteActionContext& context,
1465 : ProtobufMessage::ValidationVisitor& validation_visitor) override;
1466 190 : std::string name() const override { return "route_match_action"; }
1467 13 : ProtobufTypes::MessagePtr createEmptyConfigProto() override {
1468 13 : return std::make_unique<envoy::config::route::v3::RouteList>();
1469 13 : }
1470 : };
1471 :
1472 : DECLARE_FACTORY(RouteListMatchActionFactory);
1473 :
1474 : /**
1475 : * Wraps the route configuration which matches an incoming request headers to a backend cluster.
1476 : * This is split out mainly to help with unit testing.
1477 : */
1478 : class RouteMatcher {
1479 : public:
1480 : RouteMatcher(const envoy::config::route::v3::RouteConfiguration& config,
1481 : const CommonConfigSharedPtr& global_route_config,
1482 : Server::Configuration::ServerFactoryContext& factory_context,
1483 : ProtobufMessage::ValidationVisitor& validator, bool validate_clusters);
1484 :
1485 : RouteConstSharedPtr route(const RouteCallback& cb, const Http::RequestHeaderMap& headers,
1486 : const StreamInfo::StreamInfo& stream_info, uint64_t random_value) const;
1487 :
1488 : const VirtualHostImpl* findVirtualHost(const Http::RequestHeaderMap& headers) const;
1489 :
1490 : private:
1491 : using WildcardVirtualHosts =
1492 : std::map<int64_t, absl::node_hash_map<std::string, VirtualHostSharedPtr>, std::greater<>>;
1493 : using SubstringFunction = std::function<absl::string_view(absl::string_view, int)>;
1494 : const VirtualHostImpl* findWildcardVirtualHost(absl::string_view host,
1495 : const WildcardVirtualHosts& wildcard_virtual_hosts,
1496 : SubstringFunction substring_function) const;
1497 79 : bool ignorePortInHostMatching() const { return ignore_port_in_host_matching_; }
1498 :
1499 : Stats::ScopeSharedPtr vhost_scope_;
1500 : absl::node_hash_map<std::string, VirtualHostSharedPtr> virtual_hosts_;
1501 : // std::greater as a minor optimization to iterate from more to less specific
1502 : //
1503 : // A note on using an unordered_map versus a vector of (string, VirtualHostSharedPtr) pairs:
1504 : //
1505 : // Based on local benchmarks, each vector entry costs around 20ns for recall and (string)
1506 : // comparison with a fixed cost of about 25ns. For unordered_map, the empty map costs about 65ns
1507 : // and climbs to about 110ns once there are any entries.
1508 : //
1509 : // The break-even is 4 entries.
1510 : WildcardVirtualHosts wildcard_virtual_host_suffixes_;
1511 : WildcardVirtualHosts wildcard_virtual_host_prefixes_;
1512 :
1513 : VirtualHostSharedPtr default_virtual_host_;
1514 : const bool ignore_port_in_host_matching_{false};
1515 : };
1516 :
1517 : /**
1518 : * Shared part of the route configuration implementation.
1519 : */
1520 : class CommonConfigImpl : public CommonConfig {
1521 : public:
1522 : CommonConfigImpl(const envoy::config::route::v3::RouteConfiguration& config,
1523 : Server::Configuration::ServerFactoryContext& factory_context,
1524 : ProtobufMessage::ValidationVisitor& validator);
1525 :
1526 196 : const HeaderParser& requestHeaderParser() const {
1527 196 : if (request_headers_parser_ != nullptr) {
1528 1 : return *request_headers_parser_;
1529 1 : }
1530 195 : return HeaderParser::defaultParser();
1531 196 : }
1532 335 : const HeaderParser& responseHeaderParser() const {
1533 335 : if (response_headers_parser_ != nullptr) {
1534 202 : return *response_headers_parser_;
1535 202 : }
1536 133 : return HeaderParser::defaultParser();
1537 335 : }
1538 :
1539 40 : const RouteSpecificFilterConfig* perFilterConfig(const std::string& name) const {
1540 40 : return per_filter_configs_.get(name);
1541 40 : }
1542 427 : absl::optional<bool> filterDisabled(absl::string_view config_name) const {
1543 427 : return per_filter_configs_.disabled(config_name);
1544 427 : }
1545 :
1546 : // Router::CommonConfig
1547 208 : const std::list<Http::LowerCaseString>& internalOnlyHeaders() const override {
1548 208 : return internal_only_headers_;
1549 208 : }
1550 0 : const std::string& name() const override { return name_; }
1551 0 : bool usesVhds() const override { return uses_vhds_; }
1552 531 : bool mostSpecificHeaderMutationsWins() const override {
1553 531 : return most_specific_header_mutations_wins_;
1554 531 : }
1555 1645 : uint32_t maxDirectResponseBodySizeBytes() const override {
1556 1645 : return max_direct_response_body_size_bytes_;
1557 1645 : }
1558 1254 : const std::vector<ShadowPolicyPtr>& shadowPolicies() const { return shadow_policies_; }
1559 : ClusterSpecifierPluginSharedPtr clusterSpecifierPlugin(absl::string_view provider) const;
1560 674 : bool ignorePathParametersInPathMatching() const {
1561 674 : return ignore_path_parameters_in_path_matching_;
1562 674 : }
1563 : const envoy::config::core::v3::Metadata& metadata() const override;
1564 : const Envoy::Config::TypedMetadata& typedMetadata() const override;
1565 :
1566 : private:
1567 : std::list<Http::LowerCaseString> internal_only_headers_;
1568 : HeaderParserPtr request_headers_parser_;
1569 : HeaderParserPtr response_headers_parser_;
1570 : const std::string name_;
1571 : Stats::SymbolTable& symbol_table_;
1572 : std::vector<ShadowPolicyPtr> shadow_policies_;
1573 : // Cluster specifier plugins/providers.
1574 : absl::flat_hash_map<std::string, ClusterSpecifierPluginSharedPtr> cluster_specifier_plugins_;
1575 : PerFilterConfigs per_filter_configs_;
1576 : RouteMetadataPackPtr metadata_;
1577 : // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
1578 : const uint32_t max_direct_response_body_size_bytes_;
1579 : const bool uses_vhds_ : 1;
1580 : const bool most_specific_header_mutations_wins_ : 1;
1581 : const bool ignore_path_parameters_in_path_matching_ : 1;
1582 : };
1583 :
1584 : /**
1585 : * Implementation of Config that reads from a proto file.
1586 : */
1587 : class ConfigImpl : public Config {
1588 : public:
1589 : ConfigImpl(const envoy::config::route::v3::RouteConfiguration& config,
1590 : Server::Configuration::ServerFactoryContext& factory_context,
1591 : ProtobufMessage::ValidationVisitor& validator, bool validate_clusters_default);
1592 :
1593 0 : bool virtualHostExists(const Http::RequestHeaderMap& headers) const {
1594 0 : return route_matcher_->findVirtualHost(headers) != nullptr;
1595 0 : }
1596 :
1597 : // Router::Config
1598 : RouteConstSharedPtr route(const Http::RequestHeaderMap& headers,
1599 : const StreamInfo::StreamInfo& stream_info,
1600 92 : uint64_t random_value) const override {
1601 92 : return route(nullptr, headers, stream_info, random_value);
1602 92 : }
1603 : RouteConstSharedPtr route(const RouteCallback& cb, const Http::RequestHeaderMap& headers,
1604 : const StreamInfo::StreamInfo& stream_info,
1605 : uint64_t random_value) const override;
1606 208 : const std::list<Http::LowerCaseString>& internalOnlyHeaders() const override {
1607 208 : return shared_config_->internalOnlyHeaders();
1608 208 : }
1609 0 : const std::string& name() const override { return shared_config_->name(); }
1610 0 : bool usesVhds() const override { return shared_config_->usesVhds(); }
1611 0 : bool mostSpecificHeaderMutationsWins() const override {
1612 0 : return shared_config_->mostSpecificHeaderMutationsWins();
1613 0 : }
1614 0 : uint32_t maxDirectResponseBodySizeBytes() const override {
1615 0 : return shared_config_->maxDirectResponseBodySizeBytes();
1616 0 : }
1617 0 : const std::vector<ShadowPolicyPtr>& shadowPolicies() const {
1618 0 : return shared_config_->shadowPolicies();
1619 0 : }
1620 0 : bool ignorePathParametersInPathMatching() const {
1621 0 : return shared_config_->ignorePathParametersInPathMatching();
1622 0 : }
1623 0 : const envoy::config::core::v3::Metadata& metadata() const override {
1624 0 : return shared_config_->metadata();
1625 0 : }
1626 0 : const Envoy::Config::TypedMetadata& typedMetadata() const override {
1627 0 : return shared_config_->typedMetadata();
1628 0 : }
1629 :
1630 : private:
1631 : CommonConfigSharedPtr shared_config_;
1632 : std::unique_ptr<RouteMatcher> route_matcher_;
1633 : };
1634 :
1635 : /**
1636 : * Implementation of Config that is empty.
1637 : */
1638 : class NullConfigImpl : public Config {
1639 : public:
1640 : // Router::Config
1641 : RouteConstSharedPtr route(const Http::RequestHeaderMap&, const StreamInfo::StreamInfo&,
1642 0 : uint64_t) const override {
1643 0 : return nullptr;
1644 0 : }
1645 :
1646 : RouteConstSharedPtr route(const RouteCallback&, const Http::RequestHeaderMap&,
1647 98 : const StreamInfo::StreamInfo&, uint64_t) const override {
1648 98 : return nullptr;
1649 98 : }
1650 :
1651 98 : const std::list<Http::LowerCaseString>& internalOnlyHeaders() const override {
1652 98 : return internal_only_headers_;
1653 98 : }
1654 :
1655 0 : const std::string& name() const override { return name_; }
1656 0 : bool usesVhds() const override { return false; }
1657 0 : bool mostSpecificHeaderMutationsWins() const override { return false; }
1658 0 : uint32_t maxDirectResponseBodySizeBytes() const override { return 0; }
1659 : const envoy::config::core::v3::Metadata& metadata() const override;
1660 : const Envoy::Config::TypedMetadata& typedMetadata() const override;
1661 :
1662 : private:
1663 : std::list<Http::LowerCaseString> internal_only_headers_;
1664 : const std::string name_;
1665 : };
1666 :
1667 : } // namespace Router
1668 : } // namespace Envoy
|