1
#pragma once
2

            
3
#include <chrono>
4
#include <cstdint>
5
#include <iterator>
6
#include <map>
7
#include <memory>
8
#include <regex>
9
#include <string>
10
#include <vector>
11

            
12
#include "envoy/config/core/v3/base.pb.h"
13
#include "envoy/config/route/v3/route.pb.h"
14
#include "envoy/config/route/v3/route_components.pb.h"
15
#include "envoy/config/route/v3/route_components.pb.validate.h"
16
#include "envoy/registry/registry.h"
17
#include "envoy/router/cluster_specifier_plugin.h"
18
#include "envoy/router/router.h"
19
#include "envoy/runtime/runtime.h"
20
#include "envoy/server/filter_config.h"
21
#include "envoy/type/v3/percent.pb.h"
22
#include "envoy/upstream/cluster_manager.h"
23

            
24
#include "source/common/common/matchers.h"
25
#include "source/common/common/packed_struct.h"
26
#include "source/common/config/datasource.h"
27
#include "source/common/config/metadata.h"
28
#include "source/common/http/hash_policy.h"
29
#include "source/common/http/header_mutation.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/per_filter_config.h"
36
#include "source/common/router/retry_policy_impl.h"
37
#include "source/common/router/router_ratelimit.h"
38
#include "source/common/router/tls_context_match_criteria_impl.h"
39
#include "source/common/stats/symbol_table.h"
40

            
41
#include "absl/container/flat_hash_set.h"
42
#include "absl/container/inlined_vector.h"
43
#include "absl/container/node_hash_map.h"
44
#include "absl/types/optional.h"
45

            
46
namespace Envoy {
47
namespace Router {
48

            
49
using RouteMetadataPack = Envoy::Config::MetadataPack<HttpRouteTypedMetadataFactory>;
50
using RouteMetadataPackPtr = Envoy::Config::MetadataPackPtr<HttpRouteTypedMetadataFactory>;
51
using DefaultRouteMetadataPack = ConstSingleton<RouteMetadataPack>;
52

            
53
/**
54
 * Original port from the authority header.
55
 */
56
class OriginalConnectPort : public StreamInfo::FilterState::Object {
57
public:
58
12
  explicit OriginalConnectPort(uint32_t port) : port_(port) {}
59
12
  const uint32_t& value() const { return port_; }
60
  static const std::string& key();
61

            
62
private:
63
  const uint32_t port_;
64
};
65

            
66
/**
67
 * Base interface for something that matches a header.
68
 */
69
class Matchable {
70
public:
71
12800
  virtual ~Matchable() = default;
72

            
73
  /**
74
   * See if this object matches the incoming headers.
75
   * @param headers supplies the headers to match.
76
   * @param random_value supplies the random seed to use if a runtime choice is required. This
77
   *        allows stable choices between calls if desired.
78
   * @return true if input headers match this object.
79
   */
80
  virtual RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
81
                                      const StreamInfo::StreamInfo& stream_info,
82
                                      uint64_t random_value) const PURE;
83

            
84
  // By default, matchers do not support null Path headers.
85
21
  virtual bool supportsPathlessHeaders() const { return false; }
86
};
87

            
88
class RouteEntryImplBase;
89
using RouteEntryImplBaseConstSharedPtr = std::shared_ptr<const RouteEntryImplBase>;
90

            
91
/**
92
 * Direct response entry that does an SSL redirect.
93
 */
94
class SslRedirector : public DirectResponseEntry {
95
public:
96
  // Router::DirectResponseEntry
97
  void finalizeResponseHeaders(Http::ResponseHeaderMap&, const Formatter::Context&,
98
12
                               const StreamInfo::StreamInfo&) const override {}
99
  Http::HeaderTransforms responseHeaderTransforms(const StreamInfo::StreamInfo&,
100
                                                  bool) const override {
101
    return {};
102
  }
103
  std::string newUri(const Http::RequestHeaderMap& headers) const override;
104
12
  void rewritePathHeader(Http::RequestHeaderMap&, bool) const override {}
105
36
  Http::Code responseCode() const override { return Http::Code::MovedPermanently; }
106
  absl::string_view formatBody(const Http::RequestHeaderMap&, const Http::ResponseHeaderMap&,
107
12
                               const StreamInfo::StreamInfo&, std::string&) const override {
108
12
    return EMPTY_STRING;
109
12
  };
110
12
  absl::string_view responseContentType() const override { return EMPTY_STRING; }
111
};
112

            
113
class CommonVirtualHostImpl;
114
using CommonVirtualHostSharedPtr = std::shared_ptr<CommonVirtualHostImpl>;
115

            
116
class SslRedirectRoute : public Route {
117
public:
118
  SslRedirectRoute(VirtualHostConstSharedPtr virtual_host)
119
11588
      : virtual_host_(std::move(virtual_host)) {}
120

            
121
  // Router::Route
122
15
  const DirectResponseEntry* directResponseEntry() const override { return &SSL_REDIRECTOR; }
123
61
  const RouteEntry* routeEntry() const override { return nullptr; }
124
2
  const Decorator* decorator() const override { return nullptr; }
125
1
  const RouteTracing* tracingConfig() const override { return nullptr; }
126
1
  const RouteSpecificFilterConfig* mostSpecificPerFilterConfig(absl::string_view) const override {
127
1
    return nullptr;
128
1
  }
129
13
  absl::optional<bool> filterDisabled(absl::string_view) const override { return {}; }
130
1
  RouteSpecificFilterConfigs perFilterConfigs(absl::string_view) const override { return {}; }
131
1
  const envoy::config::core::v3::Metadata& metadata() const override { return metadata_; }
132
1
  const Envoy::Config::TypedMetadata& typedMetadata() const override { return typed_metadata_; }
133
1
  const std::string& routeName() const override { return EMPTY_STRING; }
134
  const VirtualHostConstSharedPtr& virtualHost() const override { return virtual_host_; }
135

            
136
private:
137
  const VirtualHostConstSharedPtr virtual_host_;
138

            
139
  static const SslRedirector SSL_REDIRECTOR;
140
  static const envoy::config::core::v3::Metadata metadata_;
141
  static const Envoy::Config::TypedMetadataImpl<Envoy::Config::TypedMetadataFactory>
142
      typed_metadata_;
143
};
144

            
145
/**
146
 * Implementation of CorsPolicy that reads from the proto route and virtual host config.
147
 * TODO(wbpcode): move all cors interfaces and implementation to 'extensions/filters/http/cors'.
148
 */
149
template <class ProtoType> class CorsPolicyImplBase : public CorsPolicy {
150
public:
151
  CorsPolicyImplBase(const ProtoType& config,
152
                     Server::Configuration::CommonFactoryContext& factory_context)
153
      : filter_enabled_(
154
112
            config.has_filter_enabled()
155
112
                ? std::make_unique<const envoy::config::core::v3::RuntimeFractionalPercent>(
156
22
                      config.filter_enabled())
157
112
                : nullptr),
158
        shadow_enabled_(
159
112
            config.has_shadow_enabled()
160
112
                ? std::make_unique<const envoy::config::core::v3::RuntimeFractionalPercent>(
161
2
                      config.shadow_enabled())
162
112
                : nullptr),
163
112
        loader_(factory_context.runtime()), allow_methods_(config.allow_methods()),
164
112
        allow_headers_(config.allow_headers()), expose_headers_(config.expose_headers()),
165
112
        max_age_(config.max_age()),
166
112
        allow_credentials_(PROTOBUF_GET_OPTIONAL_WRAPPED(config, allow_credentials)),
167
        allow_private_network_access_(
168
112
            PROTOBUF_GET_OPTIONAL_WRAPPED(config, allow_private_network_access)),
169
        forward_not_matching_preflights_(
170
112
            PROTOBUF_GET_OPTIONAL_WRAPPED(config, forward_not_matching_preflights)) {
171
112
    allow_origins_.reserve(config.allow_origin_string_match().size());
172
112
    for (const auto& string_match : config.allow_origin_string_match()) {
173
112
      allow_origins_.emplace_back(
174
112
          std::make_unique<Matchers::StringMatcherImpl>(string_match, factory_context));
175
112
    }
176
112
  }
177

            
178
  // Router::CorsPolicy
179
34
  const std::vector<Matchers::StringMatcherPtr>& allowOrigins() const override {
180
34
    return allow_origins_;
181
34
  };
182
10
  const std::string& allowMethods() const override { return allow_methods_; };
183
10
  const std::string& allowHeaders() const override { return allow_headers_; };
184
22
  const std::string& exposeHeaders() const override { return expose_headers_; };
185
12
  const std::string& maxAge() const override { return max_age_; };
186
24
  const absl::optional<bool>& allowCredentials() const override { return allow_credentials_; };
187
8
  const absl::optional<bool>& allowPrivateNetworkAccess() const override {
188
8
    return allow_private_network_access_;
189
8
  };
190
20
  bool enabled() const override {
191
20
    if (filter_enabled_ != nullptr) {
192
4
      return loader_.snapshot().featureEnabled(filter_enabled_->runtime_key(),
193
4
                                               filter_enabled_->default_value());
194
4
    }
195
16
    return true;
196
20
  };
197
20
  bool shadowEnabled() const override {
198
20
    if (shadow_enabled_ != nullptr) {
199
2
      return loader_.snapshot().featureEnabled(shadow_enabled_->runtime_key(),
200
2
                                               shadow_enabled_->default_value());
201
2
    }
202
18
    return false;
203
20
  };
204
4
  const absl::optional<bool>& forwardNotMatchingPreflights() const override {
205
4
    return forward_not_matching_preflights_;
206
4
  }
207

            
208
private:
209
  const std::unique_ptr<const envoy::config::core::v3::RuntimeFractionalPercent> filter_enabled_;
210
  const std::unique_ptr<const envoy::config::core::v3::RuntimeFractionalPercent> shadow_enabled_;
211
  Runtime::Loader& loader_;
212
  std::vector<Matchers::StringMatcherPtr> allow_origins_;
213
  const std::string allow_methods_;
214
  const std::string allow_headers_;
215
  const std::string expose_headers_;
216
  const std::string max_age_;
217
  absl::optional<bool> allow_credentials_;
218
  absl::optional<bool> allow_private_network_access_;
219
  absl::optional<bool> forward_not_matching_preflights_;
220
};
221
using CorsPolicyImpl = CorsPolicyImplBase<envoy::config::route::v3::CorsPolicy>;
222

            
223
using RetryPolicyConstOptRef = const OptRef<const envoy::config::route::v3::RetryPolicy>;
224
using HedgePolicyConstOptRef = const OptRef<const envoy::config::route::v3::HedgePolicy>;
225

            
226
class ConfigImpl;
227
class CommonConfigImpl;
228
using CommonConfigSharedPtr = std::shared_ptr<CommonConfigImpl>;
229

            
230
/**
231
 * Implementation of VirtualHost that reads from the proto config. This class holds all shared
232
 * data for all routes in the virtual host.
233
 */
234
class CommonVirtualHostImpl : public VirtualHost, Logger::Loggable<Logger::Id::router> {
235
public:
236
  static absl::StatusOr<std::shared_ptr<CommonVirtualHostImpl>>
237
  create(const envoy::config::route::v3::VirtualHost& virtual_host,
238
         const CommonConfigSharedPtr& global_route_config,
239
         Server::Configuration::ServerFactoryContext& factory_context, Stats::Scope& scope,
240
         ProtobufMessage::ValidationVisitor& validator);
241

            
242
  const VirtualCluster* virtualClusterFromEntries(const Http::HeaderMap& headers) const;
243
262524
  const CommonConfigImpl& globalRouteConfig() const { return *global_route_config_; }
244
44187
  const HeaderParser& requestHeaderParser() const {
245
44187
    if (request_headers_parser_ != nullptr) {
246
49
      return *request_headers_parser_;
247
49
    }
248
44138
    return HeaderParser::defaultParser();
249
44187
  }
250
41810
  const HeaderParser& responseHeaderParser() const {
251
41810
    if (response_headers_parser_ != nullptr) {
252
2781
      return *response_headers_parser_;
253
2781
    }
254
39029
    return HeaderParser::defaultParser();
255
41810
  }
256
  absl::optional<bool> filterDisabled(absl::string_view config_name) const;
257

            
258
  // Router::VirtualHost
259
10
  const CorsPolicy* corsPolicy() const override { return cors_policy_.get(); }
260
  const std::string& name() const override { return name_; }
261
73167
  Stats::StatName statName() const override { return stat_name_storage_.statName(); }
262
2
  const RateLimitPolicy& rateLimitPolicy() const override {
263
2
    if (rate_limit_policy_ != nullptr) {
264
1
      return *rate_limit_policy_;
265
1
    }
266
1
    return DefaultRateLimitPolicy::get();
267
2
  }
268
  const CommonConfig& routeConfig() const override;
269
  const RouteSpecificFilterConfig* mostSpecificPerFilterConfig(absl::string_view) const override;
270
44026
  bool includeAttemptCountInRequest() const override { return include_attempt_count_in_request_; }
271
37838
  bool includeAttemptCountInResponse() const override { return include_attempt_count_in_response_; }
272
43498
  bool includeIsTimeoutRetryHeader() const override { return include_is_timeout_retry_header_; }
273
12718
  const std::vector<ShadowPolicyPtr>& shadowPolicies() const { return shadow_policies_; }
274
12790
  const RetryPolicyConstSharedPtr& retryPolicy() const { return retry_policy_; }
275
12797
  HedgePolicyConstOptRef hedgePolicy() const {
276
12797
    if (hedge_policy_ != nullptr) {
277
3
      return *hedge_policy_;
278
3
    }
279
12794
    return absl::nullopt;
280
12797
  }
281
12771
  absl::optional<uint64_t> requestBodyBufferLimit() const { return request_body_buffer_limit_; }
282
12743
  absl::optional<uint32_t> legacyRequestBodyBufferLimit() const {
283
12743
    return per_request_buffer_limit_;
284
12743
  }
285

            
286
  RouteSpecificFilterConfigs perFilterConfigs(absl::string_view) const override;
287
  const envoy::config::core::v3::Metadata& metadata() const override;
288
  const Envoy::Config::TypedMetadata& typedMetadata() const override;
289
44100
  const VirtualCluster* virtualCluster(const Http::HeaderMap& headers) const override {
290
44100
    return virtualClusterFromEntries(headers);
291
44100
  }
292

            
293
private:
294
  CommonVirtualHostImpl(const envoy::config::route::v3::VirtualHost& virtual_host,
295
                        const CommonConfigSharedPtr& global_route_config,
296
                        Server::Configuration::ServerFactoryContext& factory_context,
297
                        Stats::Scope& scope, ProtobufMessage::ValidationVisitor& validator,
298
                        absl::Status& creation_status);
299
  struct StatNameProvider {
300
    StatNameProvider(absl::string_view name, Stats::SymbolTable& symbol_table)
301
41
        : stat_name_storage_(name, symbol_table) {}
302
    Stats::StatNameManagedStorage stat_name_storage_;
303
  };
304

            
305
  struct VirtualClusterBase : public VirtualCluster {
306
  public:
307
    VirtualClusterBase(const absl::optional<std::string>& name, Stats::StatName stat_name,
308
                       Stats::ScopeSharedPtr&& scope, const VirtualClusterStatNames& stat_names)
309
60
        : name_(name), stat_name_(stat_name), scope_(std::move(scope)),
310
60
          stats_(generateStats(*scope_, stat_names)) {}
311

            
312
    // Router::VirtualCluster
313
    // name_ and stat_name_ are two different representations for the same string, retained in
314
    // memory to avoid symbol-table locks that would be needed when converting on-the-fly.
315
24
    const absl::optional<std::string>& name() const override { return name_; }
316
84
    Stats::StatName statName() const override { return stat_name_; }
317
24
    VirtualClusterStats& stats() const override { return stats_; }
318

            
319
  private:
320
    const absl::optional<std::string> name_;
321
    const Stats::StatName stat_name_;
322
    Stats::ScopeSharedPtr scope_;
323
    mutable VirtualClusterStats stats_;
324
  };
325

            
326
  struct VirtualClusterEntry : public StatNameProvider, public VirtualClusterBase {
327
    VirtualClusterEntry(const envoy::config::route::v3::VirtualCluster& virtual_cluster,
328
                        Stats::Scope& scope, Server::Configuration::CommonFactoryContext& context,
329
                        const VirtualClusterStatNames& stat_names);
330
    std::vector<Http::HeaderUtility::HeaderDataPtr> headers_;
331
  };
332

            
333
  struct CatchAllVirtualCluster : public VirtualClusterBase {
334
    CatchAllVirtualCluster(Stats::Scope& scope, const VirtualClusterStatNames& stat_names)
335
19
        : VirtualClusterBase(absl::nullopt, stat_names.other_,
336
19
                             scope.scopeFromStatName(stat_names.other_), stat_names) {}
337
  };
338

            
339
  const std::string name_;
340
  const Stats::StatNameManagedStorage stat_name_storage_;
341
  Stats::ScopeSharedPtr vcluster_scope_;
342
  std::vector<VirtualClusterEntry> virtual_clusters_;
343
  std::unique_ptr<const RateLimitPolicyImpl> rate_limit_policy_;
344
  std::vector<ShadowPolicyPtr> shadow_policies_;
345
  std::unique_ptr<const CorsPolicyImpl> cors_policy_;
346
  // Keep an copy of the shared pointer to the shared part of the route config. This is needed
347
  // to keep the shared part alive while the virtual host is alive.
348
  const CommonConfigSharedPtr global_route_config_;
349
  HeaderParserPtr request_headers_parser_;
350
  HeaderParserPtr response_headers_parser_;
351
  std::unique_ptr<PerFilterConfigs> per_filter_configs_;
352
  RetryPolicyConstSharedPtr retry_policy_;
353
  std::unique_ptr<envoy::config::route::v3::HedgePolicy> hedge_policy_;
354
  std::unique_ptr<const CatchAllVirtualCluster> virtual_cluster_catch_all_;
355
  RouteMetadataPackPtr metadata_;
356
  const absl::optional<uint32_t> per_request_buffer_limit_;
357
  const absl::optional<uint64_t> request_body_buffer_limit_;
358
  // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
359
  const bool include_attempt_count_in_request_ : 1;
360
  const bool include_attempt_count_in_response_ : 1;
361
  const bool include_is_timeout_retry_header_ : 1;
362
};
363

            
364
/**
365
 * Virtual host that holds a collection of routes.
366
 */
367
class VirtualHostImpl : Logger::Loggable<Logger::Id::router> {
368
public:
369
  VirtualHostImpl(const envoy::config::route::v3::VirtualHost& virtual_host,
370
                  const CommonConfigSharedPtr& global_route_config,
371
                  Server::Configuration::ServerFactoryContext& factory_context, Stats::Scope& scope,
372
                  ProtobufMessage::ValidationVisitor& validator, bool validate_clusters,
373
                  absl::Status& creation_status);
374

            
375
  RouteConstSharedPtr getRouteFromEntries(const RouteCallback& cb,
376
                                          const Http::RequestHeaderMap& headers,
377
                                          const StreamInfo::StreamInfo& stream_info,
378
                                          uint64_t random_value) const;
379

            
380
  RouteConstSharedPtr
381
  getRouteFromRoutes(const RouteCallback& cb, const Http::RequestHeaderMap& headers,
382
                     const StreamInfo::StreamInfo& stream_info, uint64_t random_value,
383
                     absl::Span<const RouteEntryImplBaseConstSharedPtr> routes) const;
384

            
385
89807
  VirtualHostConstSharedPtr virtualHost() const { return shared_virtual_host_; }
386

            
387
private:
388
  enum class SslRequirements : uint8_t { None, ExternalOnly, All };
389

            
390
  CommonVirtualHostSharedPtr shared_virtual_host_;
391

            
392
  std::shared_ptr<const SslRedirectRoute> ssl_redirect_route_;
393
  SslRequirements ssl_requirements_;
394

            
395
  absl::InlinedVector<RouteEntryImplBaseConstSharedPtr, 2> routes_;
396
  Matcher::MatchTreeSharedPtr<Http::HttpMatchingData> matcher_;
397
};
398

            
399
using VirtualHostImplSharedPtr = std::shared_ptr<VirtualHostImpl>;
400
using HeaderMutationsPtr = std::unique_ptr<Http::HeaderMutations>;
401

            
402
/**
403
 * Implementation of ShadowPolicy that reads from the proto route config.
404
 */
405
class ShadowPolicyImpl : public ShadowPolicy {
406
public:
407
  using RequestMirrorPolicy = envoy::config::route::v3::RouteAction::RequestMirrorPolicy;
408

            
409
  static absl::StatusOr<std::shared_ptr<ShadowPolicyImpl>>
410
  create(const RequestMirrorPolicy& config,
411
         Server::Configuration::CommonFactoryContext& factory_context);
412

            
413
  // Router::ShadowPolicy
414
360
  const std::string& cluster() const override { return cluster_; }
415
8
  const Http::LowerCaseString& clusterHeader() const override { return cluster_header_; }
416
109
  const std::string& runtimeKey() const override { return runtime_key_; }
417
103
  const envoy::type::v3::FractionalPercent& defaultValue() const override { return default_value_; }
418
98
  absl::optional<bool> traceSampled() const override { return trace_sampled_; }
419
93
  bool disableShadowHostSuffixAppend() const override {
420
93
    return disable_shadow_host_suffix_append_ || !host_rewrite_literal_.empty();
421
93
  }
422
  const Http::HeaderEvaluator& headerEvaluator() const override;
423
149
  absl::string_view hostRewriteLiteral() const override { return host_rewrite_literal_; }
424

            
425
private:
426
  explicit ShadowPolicyImpl(const RequestMirrorPolicy& config,
427
                            Server::Configuration::CommonFactoryContext& factory_context,
428
                            absl::Status& creation_status);
429

            
430
  const std::string cluster_;
431
  const Http::LowerCaseString cluster_header_;
432
  std::string runtime_key_;
433
  envoy::type::v3::FractionalPercent default_value_;
434
  absl::optional<bool> trace_sampled_;
435
  const bool disable_shadow_host_suffix_append_;
436
  const std::string host_rewrite_literal_;
437
  HeaderMutationsPtr request_headers_mutations_;
438
};
439

            
440
/**
441
 * Implementation of HedgePolicy that reads from the proto route or virtual host config.
442
 */
443
class HedgePolicyImpl : public HedgePolicy {
444

            
445
public:
446
  explicit HedgePolicyImpl(const envoy::config::route::v3::HedgePolicy& hedge_policy);
447
  HedgePolicyImpl();
448

            
449
  // Router::HedgePolicy
450
6
  uint32_t initialRequests() const override { return initial_requests_; }
451
6
  const envoy::type::v3::FractionalPercent& additionalRequestChance() const override {
452
6
    return additional_request_chance_;
453
6
  }
454
44031
  bool hedgeOnPerTryTimeout() const override { return hedge_on_per_try_timeout_; }
455

            
456
private:
457
  const envoy::type::v3::FractionalPercent additional_request_chance_;
458
  // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
459
  const uint32_t initial_requests_;
460
  const bool hedge_on_per_try_timeout_;
461
};
462
using DefaultHedgePolicy = ConstSingleton<HedgePolicyImpl>;
463

            
464
/**
465
 * Implementation of Decorator that reads from the proto route decorator.
466
 */
467
class DecoratorImpl : public Decorator {
468
public:
469
  explicit DecoratorImpl(const envoy::config::route::v3::Decorator& decorator);
470

            
471
  // Decorator::apply
472
  void apply(Tracing::Span& span) const override;
473

            
474
  // Decorator::getOperation
475
  const std::string& getOperation() const override;
476

            
477
  // Decorator::getOperation
478
  bool propagate() const override;
479

            
480
private:
481
  const std::string operation_;
482
  const bool propagate_;
483
};
484

            
485
/**
486
 * Implementation of RouteTracing that reads from the proto route tracing.
487
 */
488
class RouteTracingImpl : public RouteTracing {
489
public:
490
  explicit RouteTracingImpl(const envoy::config::route::v3::Tracing& tracing);
491

            
492
  // RouteTracing
493
  const envoy::type::v3::FractionalPercent& getClientSampling() const override;
494
  const envoy::type::v3::FractionalPercent& getRandomSampling() const override;
495
  const envoy::type::v3::FractionalPercent& getOverallSampling() const override;
496
  const Tracing::CustomTagMap& getCustomTags() const override;
497
4
  OptRef<const Formatter::Formatter> operation() const override {
498
4
    return makeOptRefFromPtr(operation_.get());
499
4
  }
500
4
  OptRef<const Formatter::Formatter> upstreamOperation() const override {
501
4
    return makeOptRefFromPtr(upstream_operation_.get());
502
4
  }
503

            
504
private:
505
  envoy::type::v3::FractionalPercent client_sampling_;
506
  envoy::type::v3::FractionalPercent random_sampling_;
507
  envoy::type::v3::FractionalPercent overall_sampling_;
508
  Tracing::CustomTagMap custom_tags_;
509
  Formatter::FormatterPtr operation_;
510
  Formatter::FormatterPtr upstream_operation_;
511
};
512

            
513
/**
514
 * Implementation of InternalRedirectPolicy that reads from the proto
515
 * InternalRedirectPolicy of the RouteAction.
516
 */
517
class InternalRedirectPolicyImpl : public InternalRedirectPolicy {
518
public:
519
  static absl::StatusOr<std::unique_ptr<InternalRedirectPolicyImpl>>
520
  create(const envoy::config::route::v3::InternalRedirectPolicy& policy_config,
521
         ProtobufMessage::ValidationVisitor& validator, absl::string_view current_route_name);
522
  // Constructor that enables internal redirect with policy_config controlling the configurable
523
  // behaviors.
524
  // Default constructor that disables internal redirect.
525
1548
  InternalRedirectPolicyImpl() = default;
526

            
527
225509
  bool enabled() const override { return enabled_; }
528

            
529
213
  bool shouldRedirectForResponseCode(const Http::Code& response_code) const override {
530
213
    return redirect_response_codes_.contains(response_code);
531
213
  }
532

            
533
  std::vector<InternalRedirectPredicateSharedPtr> predicates() const override;
534
  const std::vector<Http::LowerCaseString>& responseHeadersToCopy() const override;
535

            
536
178
  uint32_t maxInternalRedirects() const override { return max_internal_redirects_; }
537

            
538
178
  bool isCrossSchemeRedirectAllowed() const override { return allow_cross_scheme_redirect_; }
539

            
540
private:
541
  InternalRedirectPolicyImpl(const envoy::config::route::v3::InternalRedirectPolicy& policy_config,
542
                             ProtobufMessage::ValidationVisitor& validator,
543
                             absl::string_view current_route_name, absl::Status& creation_status);
544
  absl::flat_hash_set<Http::Code> buildRedirectResponseCodes(
545
      const envoy::config::route::v3::InternalRedirectPolicy& policy_config) const;
546

            
547
  const std::string current_route_name_;
548
  const absl::flat_hash_set<Http::Code> redirect_response_codes_;
549
  std::vector<std::pair<InternalRedirectPredicateFactory*, ProtobufTypes::MessagePtr>>
550
      predicate_factories_;
551
  // Vector of header names (as a lower case string to simplify use
552
  // later on), to copy from the response that triggers the redirect
553
  // into the following request.
554
  std::vector<Http::LowerCaseString> response_headers_to_copy_;
555
  // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
556
  const uint32_t max_internal_redirects_{1};
557
  const bool enabled_{false};
558
  const bool allow_cross_scheme_redirect_{false};
559
};
560
using DefaultInternalRedirectPolicy = ConstSingleton<InternalRedirectPolicyImpl>;
561

            
562
/**
563
 * Base implementation for all route entries.q
564
 */
565
class RouteEntryImplBase : public RouteEntryAndRoute,
566
                           public Matchable,
567
                           public DirectResponseEntry,
568
                           public PathMatchCriterion,
569
                           public Matcher::ActionBase<envoy::config::route::v3::Route>,
570
                           public std::enable_shared_from_this<RouteEntryImplBase>,
571
                           Logger::Loggable<Logger::Id::router> {
572
protected:
573
  /**
574
   * @throw EnvoyException or sets creation_status if the route configuration contains any errors
575
   */
576
  RouteEntryImplBase(const CommonVirtualHostSharedPtr& vhost,
577
                     const envoy::config::route::v3::Route& route,
578
                     Server::Configuration::ServerFactoryContext& factory_context,
579
                     ProtobufMessage::ValidationVisitor& validator, absl::Status& creation_status);
580

            
581
public:
582
582799
  bool isDirectResponse() const { return direct_response_code_.has_value(); }
583

            
584
  bool isRedirect() const;
585

            
586
  bool matchRoute(const Http::RequestHeaderMap& headers, const StreamInfo::StreamInfo& stream_info,
587
                  uint64_t random_value) const;
588
  absl::Status validateClusters(const Upstream::ClusterManager& cluster_manager) const;
589

            
590
  // Router::RouteEntry
591
  const std::string& clusterName() const override;
592
  void refreshRouteCluster(const Http::RequestHeaderMap&,
593
                           const StreamInfo::StreamInfo&) const override {}
594
44027
  const RouteStatsContextOptRef routeStatsContext() const override {
595
44027
    if (route_stats_context_ != nullptr) {
596
13
      return *route_stats_context_;
597
13
    }
598
44014
    return RouteStatsContextOptRef();
599
44027
  }
600
92
  Http::Code clusterNotFoundResponseCode() const override {
601
92
    return cluster_not_found_response_code_;
602
92
  }
603
11
  const CorsPolicy* corsPolicy() const override { return cors_policy_.get(); }
604
44187
  const HeaderParser& requestHeaderParser() const {
605
44187
    if (request_headers_parser_ != nullptr) {
606
55
      return *request_headers_parser_;
607
55
    }
608
44132
    return HeaderParser::defaultParser();
609
44187
  }
610
41810
  const HeaderParser& responseHeaderParser() const {
611
41810
    if (response_headers_parser_ != nullptr) {
612
48
      return *response_headers_parser_;
613
48
    }
614
41762
    return HeaderParser::defaultParser();
615
41810
  }
616
  void finalizeRequestHeaders(Http::RequestHeaderMap& headers, const Formatter::Context& context,
617
                              const StreamInfo::StreamInfo& stream_info,
618
                              bool keep_original_host_or_path) const override;
619

            
620
  Http::HeaderTransforms requestHeaderTransforms(const StreamInfo::StreamInfo& stream_info,
621
                                                 bool do_formatting = true) const override;
622
  void finalizeResponseHeaders(Http::ResponseHeaderMap& headers, const Formatter::Context& context,
623
                               const StreamInfo::StreamInfo& stream_info) const override;
624
  Http::HeaderTransforms responseHeaderTransforms(const StreamInfo::StreamInfo& stream_info,
625
                                                  bool do_formatting = true) const override;
626
1493
  const Http::HashPolicy* hashPolicy() const override { return hash_policy_.get(); }
627

            
628
44044
  const HedgePolicy& hedgePolicy() const override {
629
44044
    if (hedge_policy_ != nullptr) {
630
15
      return *hedge_policy_;
631
15
    }
632
44029
    return DefaultHedgePolicy::get();
633
44044
  }
634

            
635
4915
  const MetadataMatchCriteria* metadataMatchCriteria() const override {
636
4915
    return metadata_match_criteria_.get();
637
4915
  }
638
90675
  const TlsContextMatchCriteria* tlsContextMatchCriteria() const override {
639
90675
    return tls_context_match_criteria_.get();
640
90675
  }
641
87163
  Upstream::ResourcePriority priority() const override { return priority_; }
642
169
  const RateLimitPolicy& rateLimitPolicy() const override {
643
169
    if (rate_limit_policy_ != nullptr) {
644
165
      return *rate_limit_policy_;
645
165
    }
646
4
    return DefaultRateLimitPolicy::get();
647
169
  }
648
131766
  const RetryPolicyConstSharedPtr& retryPolicy() const override {
649
131766
    ASSERT(retry_policy_ != nullptr);
650
131766
    return retry_policy_;
651
131766
  }
652
152921
  const InternalRedirectPolicy& internalRedirectPolicy() const override {
653
152921
    if (internal_redirect_policy_ != nullptr) {
654
799
      return *internal_redirect_policy_;
655
799
    }
656
152122
    return DefaultInternalRedirectPolicy::get();
657
152921
  }
658

            
659
2
  const PathMatcherSharedPtr& pathMatcher() const override { return path_matcher_; }
660
1
  const PathRewriterSharedPtr& pathRewriter() const override { return path_rewriter_; }
661

            
662
131766
  uint64_t requestBodyBufferLimit() const override { return request_body_buffer_limit_; }
663
54551
  const std::vector<ShadowPolicyPtr>& shadowPolicies() const override { return shadow_policies_; }
664
44022
  std::chrono::milliseconds timeout() const override { return timeout_; }
665
44274
  bool usingNewTimeouts() const override { return using_new_timeouts_; }
666

            
667
  // `OptionalTimeouts` manages various `optional` values. We pack them in a
668
  // separate data structure for memory efficiency -- avoiding overhead of
669
  // `absl::optional` per variable, and avoiding overhead of storing unset
670
  // timeouts.
671
  enum class OptionalTimeoutNames {
672
    IdleTimeout = 0,
673
    MaxStreamDuration,
674
    GrpcTimeoutHeaderMax,
675
    GrpcTimeoutHeaderOffset,
676
    MaxGrpcTimeout,
677
    GrpcTimeoutOffset,
678
    FlushTimeout,
679
  };
680
  using OptionalTimeouts = PackedStruct<std::chrono::milliseconds, 7, OptionalTimeoutNames>;
681

            
682
103797
  absl::optional<std::chrono::milliseconds> idleTimeout() const override {
683
103797
    return getOptionalTimeout<OptionalTimeoutNames::IdleTimeout>();
684
103797
  }
685
87634
  absl::optional<std::chrono::milliseconds> flushTimeout() const override {
686
87634
    return getOptionalTimeout<OptionalTimeoutNames::FlushTimeout>();
687
87634
  }
688
87629
  absl::optional<std::chrono::milliseconds> maxStreamDuration() const override {
689
87629
    return getOptionalTimeout<OptionalTimeoutNames::MaxStreamDuration>();
690
87629
  }
691
13
  absl::optional<std::chrono::milliseconds> grpcTimeoutHeaderMax() const override {
692
13
    return getOptionalTimeout<OptionalTimeoutNames::GrpcTimeoutHeaderMax>();
693
13
  }
694
7
  absl::optional<std::chrono::milliseconds> grpcTimeoutHeaderOffset() const override {
695
7
    return getOptionalTimeout<OptionalTimeoutNames::GrpcTimeoutHeaderOffset>();
696
7
  }
697
423
  absl::optional<std::chrono::milliseconds> maxGrpcTimeout() const override {
698
423
    return getOptionalTimeout<OptionalTimeoutNames::MaxGrpcTimeout>();
699
423
  }
700
5
  absl::optional<std::chrono::milliseconds> grpcTimeoutOffset() const override {
701
5
    return getOptionalTimeout<OptionalTimeoutNames::GrpcTimeoutOffset>();
702
5
  }
703

            
704
160783
  const VirtualHostConstSharedPtr& virtualHost() const override {
705
    // The method cannot return the vhost_ directly because the vhost_ has different type with
706
    // the VirtualHostConstSharedPtr and will create a temporary copy implicitly and result in error
707
    // of returning reference to local temporary object.
708
160783
    return vhost_copy_;
709
160783
  }
710
43128
  bool autoHostRewrite() const override { return auto_host_rewrite_; }
711
14
  bool appendXfh() const override { return append_xfh_; }
712
2
  const std::multimap<std::string, std::string>& opaqueConfig() const override {
713
2
    return opaque_config_;
714
2
  }
715
44
  bool includeVirtualHostRateLimits() const override { return include_vh_rate_limits_; }
716
  const envoy::config::core::v3::Metadata& metadata() const override;
717
  const Envoy::Config::TypedMetadata& typedMetadata() const override;
718
7
  const PathMatchCriterion& pathMatchCriterion() const override { return *this; }
719
44026
  bool includeAttemptCountInRequest() const override {
720
44026
    return vhost_->includeAttemptCountInRequest();
721
44026
  }
722
37838
  bool includeAttemptCountInResponse() const override {
723
37838
    return vhost_->includeAttemptCountInResponse();
724
37838
  }
725
44102
  const ConnectConfigOptRef connectConfig() const override {
726
44102
    if (connect_config_ != nullptr) {
727
829
      return *connect_config_;
728
829
    }
729
43273
    return absl::nullopt;
730
44102
  }
731
593
  const UpgradeMap& upgradeMap() const override { return upgrade_map_; }
732
43500
  const EarlyDataPolicy& earlyDataPolicy() const override { return *early_data_policy_; }
733

            
734
  // Router::DirectResponseEntry
735
  std::string newUri(const Http::RequestHeaderMap& headers) const override;
736
  void rewritePathHeader(Http::RequestHeaderMap&, bool) const override {}
737
394
  Http::Code responseCode() const override { return direct_response_code_.value(); }
738
  absl::string_view formatBody(const Http::RequestHeaderMap& request_headers,
739
                               const Http::ResponseHeaderMap& response_headers,
740
                               const StreamInfo::StreamInfo& stream_info,
741
                               std::string& body_out) const override;
742
132
  absl::string_view responseContentType() const override { return direct_response_content_type_; }
743

            
744
  // Router::Route
745
  const DirectResponseEntry* directResponseEntry() const override;
746
  const RouteEntry* routeEntry() const override;
747
43
  const Decorator* decorator() const override { return decorator_.get(); }
748
99
  const RouteTracing* tracingConfig() const override { return route_tracing_.get(); }
749
  absl::optional<bool> filterDisabled(absl::string_view config_name) const override;
750
  const RouteSpecificFilterConfig*
751
5265
  mostSpecificPerFilterConfig(absl::string_view name) const override {
752
5265
    auto* config = per_filter_configs_->get(name);
753
5265
    return config ? config : vhost_->mostSpecificPerFilterConfig(name);
754
5265
  }
755
  RouteSpecificFilterConfigs perFilterConfigs(absl::string_view) const override;
756
332
  const std::string& routeName() const override { return route_name_; }
757

            
758
  // Sanitizes the |path| before passing it to PathMatcher, if configured, this method makes the
759
  // path matching to ignore the path-parameters.
760
  absl::string_view sanitizePathBeforePathMatching(const absl::string_view path) const;
761

            
762
protected:
763
  const PathMatcherSharedPtr path_matcher_;
764

            
765
  // Path rewrite related members.
766
  const std::string prefix_rewrite_;
767
  Regex::CompiledMatcherPtr regex_rewrite_;
768
  std::string regex_rewrite_substitution_;
769
  const PathRewriterSharedPtr path_rewriter_;
770
  Formatter::FormatterPtr path_rewrite_formatter_;
771

            
772
  // Host rewrite related members.
773
  const std::string host_rewrite_;
774
  const Http::LowerCaseString host_rewrite_header_;
775
  const Regex::CompiledMatcherPtr host_rewrite_path_regex_;
776
  const std::string host_rewrite_path_regex_substitution_;
777
  Formatter::FormatterPtr host_rewrite_formatter_;
778

            
779
  std::unique_ptr<ConnectConfig> connect_config_;
780

            
781
12482
  bool case_sensitive() const { return case_sensitive_; }
782
  RouteConstSharedPtr clusterEntry(const Http::RequestHeaderMap& headers,
783
                                   const StreamInfo::StreamInfo& stream_info,
784
                                   uint64_t random_value) const;
785

            
786
  // Common logic for rewritePathHeader() of DirectResponseEntry.
787
  void finalizePathHeaderForRedirect(Http::RequestHeaderMap& headers,
788
                                     absl::string_view matched_path, bool keep_old_path) const;
789

            
790
  void finalizePathHeader(Http::RequestHeaderMap& headers, const Formatter::Context& context,
791
                          const StreamInfo::StreamInfo& stream_info, bool keep_old_host) const;
792
  void finalizeHostHeader(Http::RequestHeaderMap& headers, const Formatter::Context& context,
793
                          const StreamInfo::StreamInfo& stream_info, bool keep_old_host) const;
794

            
795
  std::string currentUrlPathAfterRewriteWithMatchedPath(const Http::RequestHeaderMap& headers,
796
                                                        const Formatter::Context& context,
797
                                                        const StreamInfo::StreamInfo& stream_info,
798
                                                        absl::string_view matched_path) const;
799

            
800
private:
801
  struct RuntimeData {
802
    std::string fractional_runtime_key_;
803
    envoy::type::v3::FractionalPercent fractional_runtime_default_;
804
  };
805

            
806
  /**
807
   * Returns an array of request header parsers which applied or will apply header transformations
808
   * to the request in this route.
809
   * @param specificity_ascend specifies whether the returned parsers will be sorted from least
810
   *        specific to most specific (global connection manager level header parser, virtual host
811
   *        level header parser and finally route-level parser.) or the reverse.
812
   * @return an array of request header parsers.
813
   */
814
  std::array<const HeaderParser*, 3> getRequestHeaderParsers(bool specificity_ascend) const;
815

            
816
  /**
817
   * Returns an array of response header parsers which applied or will apply header transformations
818
   * to the response in this route.
819
   * @param specificity_ascend specifies whether the returned parsers will be sorted from least
820
   *        specific to most specific (global connection manager level header parser, virtual host
821
   *        level header parser and finally route-level parser.) or the reverse.
822
   * @return an array of request header parsers.
823
   */
824
  std::array<const HeaderParser*, 3> getResponseHeaderParsers(bool specificity_ascend) const;
825

            
826
  std::unique_ptr<const RuntimeData>
827
  loadRuntimeData(const envoy::config::route::v3::RouteMatch& route);
828

            
829
  static std::multimap<std::string, std::string>
830
  parseOpaqueConfig(const envoy::config::route::v3::Route& route);
831

            
832
  static DecoratorConstPtr parseDecorator(const envoy::config::route::v3::Route& route);
833

            
834
  static RouteTracingConstPtr parseRouteTracing(const envoy::config::route::v3::Route& route);
835

            
836
  bool evaluateRuntimeMatch(const uint64_t random_value) const;
837

            
838
  bool evaluateTlsContextMatch(const StreamInfo::StreamInfo& stream_info) const;
839

            
840
  std::unique_ptr<HedgePolicyImpl>
841
  buildHedgePolicy(HedgePolicyConstOptRef vhost_hedge_policy,
842
                   const envoy::config::route::v3::RouteAction& route_config) const;
843

            
844
  absl::StatusOr<RetryPolicyConstSharedPtr>
845
  buildRetryPolicy(const RetryPolicyConstSharedPtr& vhost_retry_policy,
846
                   const envoy::config::route::v3::RouteAction& route_config,
847
                   ProtobufMessage::ValidationVisitor& validation_visitor,
848
                   Server::Configuration::CommonFactoryContext& factory_context) const;
849

            
850
  absl::StatusOr<std::unique_ptr<InternalRedirectPolicyImpl>>
851
  buildInternalRedirectPolicy(const envoy::config::route::v3::RouteAction& route_config,
852
                              ProtobufMessage::ValidationVisitor& validator,
853
                              absl::string_view current_route_name) const;
854

            
855
  OptionalTimeouts buildOptionalTimeouts(const envoy::config::route::v3::RouteAction& route) const;
856
  template <OptionalTimeoutNames timeout_name>
857
279508
  absl::optional<std::chrono::milliseconds> getOptionalTimeout() const {
858
279508
    const auto timeout = optional_timeouts_.get<timeout_name>();
859
279508
    if (timeout.has_value()) {
860
32364
      return *timeout;
861
32364
    }
862
247144
    return absl::nullopt;
863
279508
  }
864

            
865
  absl::StatusOr<PathMatcherSharedPtr>
866
  buildPathMatcher(const envoy::config::route::v3::Route& route,
867
                   ProtobufMessage::ValidationVisitor& validator) const;
868

            
869
  absl::StatusOr<PathRewriterSharedPtr>
870
  buildPathRewriter(const envoy::config::route::v3::Route& route,
871
                    ProtobufMessage::ValidationVisitor& validator) const;
872

            
873
  // Default timeout is 15s if nothing is specified in the route config.
874
  static const uint64_t DEFAULT_ROUTE_TIMEOUT_MS = 15000;
875

            
876
  std::unique_ptr<const CorsPolicyImpl> cors_policy_;
877
  // Keep an copy of the shared pointer to the shared part of the virtual host. This is needed
878
  // to keep the shared part alive while the route is alive.
879
  const CommonVirtualHostSharedPtr vhost_;
880
  // Same with vhost_ but this could be returned as reference. vhost_ is kept to access the
881
  // methods that not exposed in the VirtualHost.
882
  const VirtualHostConstSharedPtr vhost_copy_;
883
  const std::string cluster_name_;
884
  RouteStatsContextPtr route_stats_context_;
885
  ClusterSpecifierPluginSharedPtr cluster_specifier_plugin_;
886
  const std::chrono::milliseconds timeout_;
887
  const OptionalTimeouts optional_timeouts_;
888
  Runtime::Loader& loader_;
889
  std::unique_ptr<const RuntimeData> runtime_;
890
  std::unique_ptr<const ::Envoy::Http::Utility::RedirectConfig> redirect_config_;
891
  std::unique_ptr<const HedgePolicyImpl> hedge_policy_;
892
  RetryPolicyConstSharedPtr retry_policy_;
893
  std::unique_ptr<const InternalRedirectPolicyImpl> internal_redirect_policy_;
894
  std::unique_ptr<const RateLimitPolicyImpl> rate_limit_policy_;
895
  std::vector<ShadowPolicyPtr> shadow_policies_;
896
  std::vector<Http::HeaderUtility::HeaderDataPtr> config_headers_;
897
  std::vector<ConfigUtility::QueryParameterMatcherPtr> config_query_parameters_;
898
  std::vector<ConfigUtility::CookieMatcherPtr> config_cookies_;
899
  absl::flat_hash_set<absl::string_view> config_cookie_names_;
900

            
901
  UpgradeMap upgrade_map_;
902
  std::unique_ptr<const Http::HashPolicyImpl> hash_policy_;
903
  MetadataMatchCriteriaConstPtr metadata_match_criteria_;
904
  TlsContextMatchCriteriaConstPtr tls_context_match_criteria_;
905
  HeaderParserPtr request_headers_parser_;
906
  HeaderParserPtr response_headers_parser_;
907
  RouteMetadataPackPtr metadata_;
908
  const std::vector<Envoy::Matchers::MetadataMatcher> dynamic_metadata_;
909
  const std::vector<Envoy::Matchers::FilterStateMatcher> filter_state_;
910

            
911
  // TODO(danielhochman): refactor multimap into unordered_map since JSON is unordered map.
912
  const std::multimap<std::string, std::string> opaque_config_;
913

            
914
  const DecoratorConstPtr decorator_;
915
  const RouteTracingConstPtr route_tracing_;
916
  Envoy::Config::DataSource::DataSourceProviderPtr<std::string> direct_response_body_provider_;
917
  Formatter::FormatterPtr direct_response_body_formatter_;
918
  std::string direct_response_content_type_;
919
  std::unique_ptr<PerFilterConfigs> per_filter_configs_;
920
  const std::string route_name_;
921
  TimeSource& time_source_;
922
  EarlyDataPolicyPtr early_data_policy_;
923

            
924
  const uint64_t request_body_buffer_limit_{std::numeric_limits<uint64_t>::max()};
925
  const absl::optional<Http::Code> direct_response_code_;
926
  // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
927
  const Http::Code cluster_not_found_response_code_;
928
  const Upstream::ResourcePriority priority_;
929
  const bool auto_host_rewrite_ : 1;
930
  const bool append_xfh_ : 1;
931
  const bool using_new_timeouts_ : 1;
932
  const bool match_grpc_ : 1;
933
  const bool case_sensitive_ : 1;
934
  bool include_vh_rate_limits_ : 1;
935
};
936

            
937
/**
938
 * Route entry implementation for uri template match based routing.
939
 */
940
class UriTemplateMatcherRouteEntryImpl : public RouteEntryImplBase {
941
public:
942
  // Router::PathMatchCriterion
943
1
  const std::string& matcher() const override { return uri_template_; }
944
1
  PathMatchType matchType() const override { return PathMatchType::Template; }
945

            
946
  // Router::Matchable
947
  RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
948
                              const StreamInfo::StreamInfo& stream_info,
949
                              uint64_t random_value) const override;
950

            
951
  // Router::DirectResponseEntry
952
  void rewritePathHeader(Http::RequestHeaderMap& headers,
953
                         bool insert_envoy_original_path) const override;
954

            
955
  // Router::RouteEntry
956
  std::string currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers,
957
                                         const Formatter::Context& context,
958
                                         const StreamInfo::StreamInfo& stream_info) const override;
959

            
960
private:
961
  friend class RouteCreator;
962

            
963
  UriTemplateMatcherRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
964
                                   const envoy::config::route::v3::Route& route,
965
                                   Server::Configuration::ServerFactoryContext& factory_context,
966
                                   ProtobufMessage::ValidationVisitor& validator,
967
                                   absl::Status& creation_status);
968

            
969
  const std::string uri_template_;
970
};
971

            
972
/**
973
 * Route entry implementation for prefix path match routing.
974
 */
975
class PrefixRouteEntryImpl : public RouteEntryImplBase {
976
public:
977
  // Router::PathMatchCriterion
978
43725
  const std::string& matcher() const override { return path_matcher_->stringRepresentation(); }
979
1
  PathMatchType matchType() const override { return PathMatchType::Prefix; }
980

            
981
  // Router::Matchable
982
  RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
983
                              const StreamInfo::StreamInfo& stream_info,
984
                              uint64_t random_value) const override;
985

            
986
  // Router::DirectResponseEntry
987
  void rewritePathHeader(Http::RequestHeaderMap& headers,
988
                         bool insert_envoy_original_path) const override;
989

            
990
  // Router::RouteEntry
991
  std::string currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers,
992
                                         const Formatter::Context& context,
993
                                         const StreamInfo::StreamInfo& stream_info) const override;
994

            
995
private:
996
  friend class RouteCreator;
997
  PrefixRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
998
                       const envoy::config::route::v3::Route& route,
999
                       Server::Configuration::ServerFactoryContext& factory_context,
                       ProtobufMessage::ValidationVisitor& validator,
                       absl::Status& creation_status);
  const Matchers::PathMatcherConstSharedPtr path_matcher_;
};
/**
 * Route entry implementation for exact path match routing.
 */
class PathRouteEntryImpl : public RouteEntryImplBase {
public:
  // Router::PathMatchCriterion
99
  const std::string& matcher() const override { return path_matcher_->stringRepresentation(); }
1
  PathMatchType matchType() const override { return PathMatchType::Exact; }
  // Router::Matchable
  RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
                              const StreamInfo::StreamInfo& stream_info,
                              uint64_t random_value) const override;
  // Router::DirectResponseEntry
  void rewritePathHeader(Http::RequestHeaderMap& headers,
                         bool insert_envoy_original_path) const override;
  // Router::RouteEntry
  std::string currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers,
                                         const Formatter::Context& context,
                                         const StreamInfo::StreamInfo& stream_info) const override;
private:
  friend class RouteCreator;
  PathRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
                     const envoy::config::route::v3::Route& route,
                     Server::Configuration::ServerFactoryContext& factory_context,
                     ProtobufMessage::ValidationVisitor& validator, absl::Status& creation_status);
  const Matchers::PathMatcherConstSharedPtr path_matcher_;
};
/**
 * Route entry implementation for regular expression match routing.
 */
class RegexRouteEntryImpl : public RouteEntryImplBase {
public:
  // Router::PathMatchCriterion
1
  const std::string& matcher() const override { return path_matcher_->stringRepresentation(); }
1
  PathMatchType matchType() const override { return PathMatchType::Regex; }
  // Router::Matchable
  RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
                              const StreamInfo::StreamInfo& stream_info,
                              uint64_t random_value) const override;
  // Router::DirectResponseEntry
  void rewritePathHeader(Http::RequestHeaderMap& headers,
                         bool insert_envoy_original_path) const override;
  // Router::RouteEntry
  std::string currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers,
                                         const Formatter::Context& context,
                                         const StreamInfo::StreamInfo& stream_info) const override;
private:
  friend class RouteCreator;
  RegexRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
                      const envoy::config::route::v3::Route& route,
                      Server::Configuration::ServerFactoryContext& factory_context,
                      ProtobufMessage::ValidationVisitor& validator, absl::Status& creation_status);
  const Matchers::PathMatcherConstSharedPtr path_matcher_;
};
/**
 * Route entry implementation for CONNECT requests.
 */
class ConnectRouteEntryImpl : public RouteEntryImplBase {
public:
  // Router::PathMatchCriterion
1
  const std::string& matcher() const override { return EMPTY_STRING; }
1
  PathMatchType matchType() const override { return PathMatchType::None; }
  // Router::Matchable
  RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
                              const StreamInfo::StreamInfo& stream_info,
                              uint64_t random_value) const override;
  // Router::DirectResponseEntry
  void rewritePathHeader(Http::RequestHeaderMap&, bool) const override;
  // Router::RouteEntry
  std::string currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers,
                                         const Formatter::Context& context,
                                         const StreamInfo::StreamInfo& stream_info) const override;
430
  bool supportsPathlessHeaders() const override { return true; }
private:
  friend class RouteCreator;
  ConnectRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
                        const envoy::config::route::v3::Route& route,
                        Server::Configuration::ServerFactoryContext& factory_context,
                        ProtobufMessage::ValidationVisitor& validator,
                        absl::Status& creation_status);
};
/**
 * Route entry implementation for path separated prefix match routing.
 */
class PathSeparatedPrefixRouteEntryImpl : public RouteEntryImplBase {
public:
  // Router::PathMatchCriterion
24
  const std::string& matcher() const override { return path_matcher_->stringRepresentation(); }
1
  PathMatchType matchType() const override { return PathMatchType::PathSeparatedPrefix; }
  // Router::Matchable
  RouteConstSharedPtr matches(const Http::RequestHeaderMap& headers,
                              const StreamInfo::StreamInfo& stream_info,
                              uint64_t random_value) const override;
  // Router::DirectResponseEntry
  void rewritePathHeader(Http::RequestHeaderMap& headers,
                         bool insert_envoy_original_path) const override;
  // Router::RouteEntry
  std::string currentUrlPathAfterRewrite(const Http::RequestHeaderMap& headers,
                                         const Formatter::Context& context,
                                         const StreamInfo::StreamInfo& stream_info) const override;
private:
  friend class RouteCreator;
  PathSeparatedPrefixRouteEntryImpl(const CommonVirtualHostSharedPtr& vhost,
                                    const envoy::config::route::v3::Route& route,
                                    Server::Configuration::ServerFactoryContext& factory_context,
                                    ProtobufMessage::ValidationVisitor& validator,
                                    absl::Status& creation_status);
  const Matchers::PathMatcherConstSharedPtr path_matcher_;
};
// Contextual information used to construct the route actions for a match tree.
struct RouteActionContext {
  const CommonVirtualHostSharedPtr& vhost;
  Server::Configuration::ServerFactoryContext& factory_context;
};
// Action used with the matching tree to specify route to use for an incoming stream.
class RouteMatchAction : public Matcher::ActionBase<envoy::config::route::v3::Route> {
public:
  explicit RouteMatchAction(RouteEntryImplBaseConstSharedPtr route) : route_(std::move(route)) {}
  RouteEntryImplBaseConstSharedPtr route() const { return route_; }
private:
  const RouteEntryImplBaseConstSharedPtr route_;
};
// Registered factory for RouteMatchAction.
class RouteMatchActionFactory : public Matcher::ActionFactory<RouteActionContext> {
public:
  Matcher::ActionConstSharedPtr
  createAction(const Protobuf::Message& config, RouteActionContext& context,
               ProtobufMessage::ValidationVisitor& validation_visitor) override;
1314
  std::string name() const override { return "route"; }
15
  ProtobufTypes::MessagePtr createEmptyConfigProto() override {
15
    return std::make_unique<envoy::config::route::v3::Route>();
15
  }
};
DECLARE_FACTORY(RouteMatchActionFactory);
// Similar to RouteMatchAction, but accepts v3::RouteList instead of v3::Route.
class RouteListMatchAction : public Matcher::ActionBase<envoy::config::route::v3::RouteList> {
public:
  explicit RouteListMatchAction(std::vector<RouteEntryImplBaseConstSharedPtr> routes)
3
      : routes_(std::move(routes)) {}
6
  const std::vector<RouteEntryImplBaseConstSharedPtr>& routes() const { return routes_; }
private:
  const std::vector<RouteEntryImplBaseConstSharedPtr> routes_;
};
// Registered factory for RouteListMatchAction.
class RouteListMatchActionFactory : public Matcher::ActionFactory<RouteActionContext> {
public:
  Matcher::ActionConstSharedPtr
  createAction(const Protobuf::Message& config, RouteActionContext& context,
               ProtobufMessage::ValidationVisitor& validation_visitor) override;
1314
  std::string name() const override { return "route_match_action"; }
7
  ProtobufTypes::MessagePtr createEmptyConfigProto() override {
7
    return std::make_unique<envoy::config::route::v3::RouteList>();
7
  }
};
DECLARE_FACTORY(RouteListMatchActionFactory);
/**
 * Wraps the route configuration which matches an incoming request headers to a backend cluster.
 * This is split out mainly to help with unit testing.
 */
class RouteMatcher {
public:
  static absl::StatusOr<std::unique_ptr<RouteMatcher>>
  create(const envoy::config::route::v3::RouteConfiguration& config,
         const CommonConfigSharedPtr& global_route_config,
         Server::Configuration::ServerFactoryContext& factory_context,
         ProtobufMessage::ValidationVisitor& validator, bool validate_clusters);
  VirtualHostRoute route(const RouteCallback& cb, const Http::RequestHeaderMap& headers,
                         const StreamInfo::StreamInfo& stream_info, uint64_t random_value) const;
  const VirtualHostImpl* findVirtualHost(const Http::RequestHeaderMap& headers) const;
private:
  RouteMatcher(const envoy::config::route::v3::RouteConfiguration& config,
               const CommonConfigSharedPtr& global_route_config,
               Server::Configuration::ServerFactoryContext& factory_context,
               ProtobufMessage::ValidationVisitor& validator, bool validate_clusters,
               absl::Status& creation_status);
  using WildcardVirtualHosts =
      std::map<int64_t, absl::node_hash_map<std::string, VirtualHostImplSharedPtr>, std::greater<>>;
  using SubstringFunction = std::function<absl::string_view(absl::string_view, int)>;
  const VirtualHostImpl* findWildcardVirtualHost(absl::string_view host,
                                                 const WildcardVirtualHosts& wildcard_virtual_hosts,
                                                 SubstringFunction substring_function) const;
4084
  bool ignorePortInHostMatching() const { return ignore_port_in_host_matching_; }
  Stats::ScopeSharedPtr vhost_scope_;
  absl::node_hash_map<std::string, VirtualHostImplSharedPtr> virtual_hosts_;
  // std::greater as a minor optimization to iterate from more to less specific
  //
  // A note on using an unordered_map versus a vector of (string, VirtualHostImplSharedPtr) pairs:
  //
  // Based on local benchmarks, each vector entry costs around 20ns for recall and (string)
  // comparison with a fixed cost of about 25ns. For unordered_map, the empty map costs about 65ns
  // and climbs to about 110ns once there are any entries.
  //
  // The break-even is 4 entries.
  WildcardVirtualHosts wildcard_virtual_host_suffixes_;
  WildcardVirtualHosts wildcard_virtual_host_prefixes_;
  VirtualHostImplSharedPtr default_virtual_host_;
  const bool ignore_port_in_host_matching_{false};
  const Http::LowerCaseString vhost_header_;
};
/**
 * Shared part of the route configuration implementation.
 */
class CommonConfigImpl : public CommonConfig {
public:
  static absl::StatusOr<std::shared_ptr<CommonConfigImpl>>
  create(const envoy::config::route::v3::RouteConfiguration& config,
         Server::Configuration::ServerFactoryContext& factory_context,
         ProtobufMessage::ValidationVisitor& validator);
44187
  const HeaderParser& requestHeaderParser() const {
44187
    if (request_headers_parser_ != nullptr) {
42
      return *request_headers_parser_;
42
    }
44145
    return HeaderParser::defaultParser();
44187
  }
41810
  const HeaderParser& responseHeaderParser() const {
41810
    if (response_headers_parser_ != nullptr) {
98
      return *response_headers_parser_;
98
    }
41712
    return HeaderParser::defaultParser();
41810
  }
6310
  const RouteSpecificFilterConfig* perFilterConfig(absl::string_view name) const {
6310
    return per_filter_configs_->get(name);
6310
  }
98505
  absl::optional<bool> filterDisabled(absl::string_view config_name) const {
98505
    return per_filter_configs_->disabled(config_name);
98505
  }
  // Router::CommonConfig
87842
  const std::vector<Http::LowerCaseString>& internalOnlyHeaders() const override {
87842
    return internal_only_headers_;
87842
  }
50
  const std::string& name() const override { return name_; }
25
  bool usesVhds() const override { return uses_vhds_; }
85999
  bool mostSpecificHeaderMutationsWins() const override {
85999
    return most_specific_header_mutations_wins_;
85999
  }
466
  uint32_t maxDirectResponseBodySizeBytes() const override {
466
    return max_direct_response_body_size_bytes_;
466
  }
11591
  const std::vector<ShadowPolicyPtr>& shadowPolicies() const { return shadow_policies_; }
  absl::StatusOr<ClusterSpecifierPluginSharedPtr>
  clusterSpecifierPlugin(absl::string_view provider) const;
90064
  bool ignorePathParametersInPathMatching() const {
90064
    return ignore_path_parameters_in_path_matching_;
90064
  }
  const envoy::config::core::v3::Metadata& metadata() const override;
  const Envoy::Config::TypedMetadata& typedMetadata() const override;
private:
  CommonConfigImpl(const envoy::config::route::v3::RouteConfiguration& config,
                   Server::Configuration::ServerFactoryContext& factory_context,
                   ProtobufMessage::ValidationVisitor& validator, absl::Status& creation_status);
  std::vector<Http::LowerCaseString> internal_only_headers_;
  HeaderParserPtr request_headers_parser_;
  HeaderParserPtr response_headers_parser_;
  const std::string name_;
  Stats::SymbolTable& symbol_table_;
  std::vector<ShadowPolicyPtr> shadow_policies_;
  // Cluster specifier plugins/providers.
  absl::flat_hash_map<std::string, ClusterSpecifierPluginSharedPtr> cluster_specifier_plugins_;
  std::unique_ptr<PerFilterConfigs> per_filter_configs_;
  RouteMetadataPackPtr metadata_;
  // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
  const uint32_t max_direct_response_body_size_bytes_;
  const bool uses_vhds_ : 1;
  const bool most_specific_header_mutations_wins_ : 1;
  const bool ignore_path_parameters_in_path_matching_ : 1;
};
/**
 * Implementation of Config that reads from a proto file.
 */
class ConfigImpl : public Config {
public:
  static absl::StatusOr<std::shared_ptr<ConfigImpl>>
  create(const envoy::config::route::v3::RouteConfiguration& config,
         Server::Configuration::ServerFactoryContext& factory_context,
         ProtobufMessage::ValidationVisitor& validator, bool validate_clusters_default);
24
  bool virtualHostExists(const Http::RequestHeaderMap& headers) const {
24
    return route_matcher_->findVirtualHost(headers) != nullptr;
24
  }
  // Router::Config
  VirtualHostRoute route(const Http::RequestHeaderMap& headers,
                         const StreamInfo::StreamInfo& stream_info,
713
                         uint64_t random_value) const override {
713
    return route(nullptr, headers, stream_info, random_value);
713
  }
  VirtualHostRoute route(const RouteCallback& cb, const Http::RequestHeaderMap& headers,
                         const StreamInfo::StreamInfo& stream_info,
                         uint64_t random_value) const override;
87842
  const std::vector<Http::LowerCaseString>& internalOnlyHeaders() const override {
87842
    return shared_config_->internalOnlyHeaders();
87842
  }
48
  const std::string& name() const override { return shared_config_->name(); }
25
  bool usesVhds() const override { return shared_config_->usesVhds(); }
1
  bool mostSpecificHeaderMutationsWins() const override {
1
    return shared_config_->mostSpecificHeaderMutationsWins();
1
  }
1
  uint32_t maxDirectResponseBodySizeBytes() const override {
1
    return shared_config_->maxDirectResponseBodySizeBytes();
1
  }
1
  const std::vector<ShadowPolicyPtr>& shadowPolicies() const {
1
    return shared_config_->shadowPolicies();
1
  }
1
  bool ignorePathParametersInPathMatching() const {
1
    return shared_config_->ignorePathParametersInPathMatching();
1
  }
  const envoy::config::core::v3::Metadata& metadata() const override {
    return shared_config_->metadata();
  }
  const Envoy::Config::TypedMetadata& typedMetadata() const override {
    return shared_config_->typedMetadata();
  }
protected:
  ConfigImpl(const envoy::config::route::v3::RouteConfiguration& config,
             Server::Configuration::ServerFactoryContext& factory_context,
             ProtobufMessage::ValidationVisitor& validator, bool validate_clusters_default,
             absl::Status& creation_status);
private:
  CommonConfigSharedPtr shared_config_;
  std::unique_ptr<RouteMatcher> route_matcher_;
};
/**
 * Implementation of Config that is empty.
 */
class NullConfigImpl : public Config {
public:
  // Router::Config
  VirtualHostRoute route(const Http::RequestHeaderMap&, const StreamInfo::StreamInfo&,
2
                         uint64_t) const override {
2
    return {};
2
  }
  VirtualHostRoute route(const RouteCallback&, const Http::RequestHeaderMap&,
526
                         const StreamInfo::StreamInfo&, uint64_t) const override {
526
    return {};
526
  }
527
  const std::vector<Http::LowerCaseString>& internalOnlyHeaders() const override {
527
    return internal_only_headers_;
527
  }
54
  const std::string& name() const override { return name_; }
1
  bool usesVhds() const override { return false; }
1
  bool mostSpecificHeaderMutationsWins() const override { return false; }
1
  uint32_t maxDirectResponseBodySizeBytes() const override { return 0; }
  const envoy::config::core::v3::Metadata& metadata() const override;
  const Envoy::Config::TypedMetadata& typedMetadata() const override;
private:
  std::vector<Http::LowerCaseString> internal_only_headers_;
  const std::string name_;
};
} // namespace Router
} // namespace Envoy