Coverage Report

Created: 2024-09-19 09:45

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