Coverage Report

Created: 2023-11-12 09:30

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