Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/common/router/router.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <chrono>
4
#include <cstdint>
5
#include <functional>
6
#include <memory>
7
#include <optional>
8
#include <string>
9
10
#include "envoy/common/random_generator.h"
11
#include "envoy/extensions/filters/http/router/v3/router.pb.h"
12
#include "envoy/http/codec.h"
13
#include "envoy/http/codes.h"
14
#include "envoy/http/filter.h"
15
#include "envoy/http/filter_factory.h"
16
#include "envoy/http/hash_policy.h"
17
#include "envoy/http/stateful_session.h"
18
#include "envoy/local_info/local_info.h"
19
#include "envoy/router/router_filter_interface.h"
20
#include "envoy/router/shadow_writer.h"
21
#include "envoy/runtime/runtime.h"
22
#include "envoy/server/factory_context.h"
23
#include "envoy/server/filter_config.h"
24
#include "envoy/stats/scope.h"
25
#include "envoy/stats/stats_macros.h"
26
#include "envoy/stream_info/stream_info.h"
27
#include "envoy/upstream/cluster_manager.h"
28
29
#include "source/common/access_log/access_log_impl.h"
30
#include "source/common/buffer/watermark_buffer.h"
31
#include "source/common/common/cleanup.h"
32
#include "source/common/common/hash.h"
33
#include "source/common/common/hex.h"
34
#include "source/common/common/linked_object.h"
35
#include "source/common/common/logger.h"
36
#include "source/common/config/utility.h"
37
#include "source/common/config/well_known_names.h"
38
#include "source/common/http/filter_chain_helper.h"
39
#include "source/common/http/utility.h"
40
#include "source/common/router/config_impl.h"
41
#include "source/common/router/context_impl.h"
42
#include "source/common/router/upstream_request.h"
43
#include "source/common/stats/symbol_table.h"
44
#include "source/common/stream_info/stream_info_impl.h"
45
#include "source/common/upstream/load_balancer_impl.h"
46
#include "source/common/upstream/upstream_factory_context_impl.h"
47
48
namespace Envoy {
49
namespace Router {
50
51
/**
52
 * Struct definition for all router filter stats. @see stats_macros.h
53
 */
54
MAKE_STATS_STRUCT(FilterStats, StatNames, ALL_ROUTER_STATS);
55
56
/**
57
 * Router filter utilities split out for ease of testing.
58
 */
59
class FilterUtility {
60
public:
61
  struct HedgingParams {
62
    bool hedge_on_per_try_timeout_ : 1;
63
  };
64
65
  class StrictHeaderChecker {
66
  public:
67
    struct HeaderCheckResult {
68
      bool valid_ = true;
69
      const Http::HeaderEntry* entry_;
70
    };
71
72
    /**
73
     * Determine whether a given header's value passes the strict validation
74
     * defined for that header.
75
     * @param headers supplies the headers from which to get the target header.
76
     * @param target_header is the header to be validated.
77
     * @return HeaderCheckResult containing the entry for @param target_header
78
     *         and valid_ set to FALSE if @param target_header is set to an
79
     *         invalid value. If @param target_header doesn't appear in
80
     *         @param headers, return a result with valid_ set to TRUE.
81
     */
82
    static const HeaderCheckResult checkHeader(Http::RequestHeaderMap& headers,
83
                                               const Http::LowerCaseString& target_header);
84
85
    using ParseRetryFlagsFunc = std::function<std::pair<uint32_t, bool>(absl::string_view)>;
86
87
  private:
88
    static HeaderCheckResult hasValidRetryFields(const Http::HeaderEntry* header_entry,
89
0
                                                 const ParseRetryFlagsFunc& parse_fn) {
90
0
      HeaderCheckResult r;
91
0
      if (header_entry) {
92
0
        const auto flags_and_validity = parse_fn(header_entry->value().getStringView());
93
0
        r.valid_ = flags_and_validity.second;
94
0
        r.entry_ = header_entry;
95
0
      }
96
0
      return r;
97
0
    }
98
99
0
    static HeaderCheckResult isInteger(const Http::HeaderEntry* header_entry) {
100
0
      HeaderCheckResult r;
101
0
      if (header_entry) {
102
0
        uint64_t out;
103
0
        r.valid_ = absl::SimpleAtoi(header_entry->value().getStringView(), &out);
104
0
        r.entry_ = header_entry;
105
0
      }
106
0
      return r;
107
0
    }
108
  };
109
110
  /**
111
   * Returns response_time / timeout, as a  percentage as [0, 100]. Returns 0
112
   * if there is no timeout.
113
   * @param response_time supplies the response time thus far.
114
   * @param timeout supplies  the timeout to get the percentage of.
115
   * @return the percentage of timeout [0, 100] for stats use.
116
   */
117
  static uint64_t percentageOfTimeout(const std::chrono::milliseconds response_time,
118
                                      const std::chrono::milliseconds timeout);
119
120
  /**
121
   * Set the :scheme header using the best information available. In order this is
122
   * - existing scheme header if valid
123
   * - x-forwarded-proto header if valid
124
   * - security of downstream connection
125
   */
126
  static void setUpstreamScheme(Http::RequestHeaderMap& headers, bool downstream_secure);
127
128
  /**
129
   * Determine whether a request should be shadowed.
130
   * @param policy supplies the route's shadow policy.
131
   * @param runtime supplies the runtime to lookup the shadow key in.
132
   * @param stable_random supplies the random number to use when determining whether shadowing
133
   *        should take place.
134
   * @return TRUE if shadowing should take place.
135
   */
136
  static bool shouldShadow(const ShadowPolicy& policy, Runtime::Loader& runtime,
137
                           uint64_t stable_random);
138
139
  /**
140
   * Determine the final timeout to use based on the route as well as the request headers.
141
   * @param route supplies the request route.
142
   * @param request_headers supplies the request headers.
143
   * @param insert_envoy_expected_request_timeout_ms insert
144
   *        x-envoy-expected-request-timeout-ms?
145
   * @param grpc_request tells if the request is a gRPC request.
146
   * @return TimeoutData for both the global and per try timeouts.
147
   */
148
  static TimeoutData finalTimeout(const RouteEntry& route, Http::RequestHeaderMap& request_headers,
149
                                  bool insert_envoy_expected_request_timeout_ms, bool grpc_request,
150
                                  bool per_try_timeout_hedging_enabled,
151
                                  bool respect_expected_rq_timeout);
152
153
  /**
154
   * Set the x-envoy-expected-request-timeout-ms and grpc-timeout headers if needed.
155
   * @param elapsed_time time elapsed since completion of the downstream request
156
   * @param timeout final TimeoutData to use for the request
157
   * @param request_headers the request headers to modify
158
   * @param insert_envoy_expected_request_timeout_ms insert
159
   *        x-envoy-expected-request-timeout-ms?
160
   * @param grpc_request tells if the request is a gRPC request.
161
   * @param per_try_timeout_headging_enabled is request hedging enabled?
162
   */
163
  static void setTimeoutHeaders(uint64_t elapsed_time, const TimeoutData& timeout,
164
                                const RouteEntry& route, Http::RequestHeaderMap& request_headers,
165
                                bool insert_envoy_expected_request_timeout_ms, bool grpc_request,
166
                                bool per_try_timeout_hedging_enabled);
167
168
  /**
169
   * Try to parse a header entry that may have a timeout field
170
   *
171
   * @param header_timeout_entry header entry which may contain a timeout value.
172
   * @return result timeout value from header. It will return nullopt if parse failed.
173
   */
174
  static absl::optional<std::chrono::milliseconds>
175
  tryParseHeaderTimeout(const Http::HeaderEntry& header_timeout_entry);
176
177
  /**
178
   * Try to set global timeout.
179
   *
180
   * @param header_timeout_entry header entry which may contain a timeout value.
181
   * @param timeout timeout data to set from header timeout entry.
182
   */
183
  static void trySetGlobalTimeout(const Http::HeaderEntry& header_timeout_entry,
184
                                  TimeoutData& timeout);
185
186
  /**
187
   * Determine the final hedging settings after applying randomized behavior.
188
   * @param route supplies the request route.
189
   * @param request_headers supplies the request headers.
190
   * @return HedgingParams the final parameters to use for request hedging.
191
   */
192
  static HedgingParams finalHedgingParams(const RouteEntry& route,
193
                                          Http::RequestHeaderMap& request_headers);
194
};
195
196
/**
197
 * Configuration for the router filter.
198
 */
199
class FilterConfig : Http::FilterChainFactory {
200
public:
201
  FilterConfig(Stats::StatName stat_prefix, const LocalInfo::LocalInfo& local_info,
202
               Stats::Scope& scope, Upstream::ClusterManager& cm, Runtime::Loader& runtime,
203
               Random::RandomGenerator& random, ShadowWriterPtr&& shadow_writer,
204
               bool emit_dynamic_stats, bool start_child_span, bool suppress_envoy_headers,
205
               bool respect_expected_rq_timeout, bool suppress_grpc_request_failure_code_stats,
206
               bool flush_upstream_log_on_upstream_stream,
207
               const Protobuf::RepeatedPtrField<std::string>& strict_check_headers,
208
               TimeSource& time_source, Http::Context& http_context,
209
               Router::Context& router_context)
210
      : router_context_(router_context), scope_(scope), local_info_(local_info), cm_(cm),
211
        runtime_(runtime), default_stats_(router_context_.statNames(), scope_, stat_prefix),
212
        async_stats_(router_context_.statNames(), scope, http_context.asyncClientStatPrefix()),
213
        random_(random), emit_dynamic_stats_(emit_dynamic_stats),
214
        start_child_span_(start_child_span), suppress_envoy_headers_(suppress_envoy_headers),
215
        respect_expected_rq_timeout_(respect_expected_rq_timeout),
216
        suppress_grpc_request_failure_code_stats_(suppress_grpc_request_failure_code_stats),
217
        flush_upstream_log_on_upstream_stream_(flush_upstream_log_on_upstream_stream),
218
        http_context_(http_context), zone_name_(local_info_.zoneStatName()),
219
3.51k
        shadow_writer_(std::move(shadow_writer)), time_source_(time_source) {
220
3.51k
    if (!strict_check_headers.empty()) {
221
4
      strict_check_headers_ = std::make_unique<HeaderVector>();
222
4
      for (const auto& header : strict_check_headers) {
223
4
        strict_check_headers_->emplace_back(Http::LowerCaseString(header));
224
4
      }
225
4
    }
226
3.51k
  }
227
228
  FilterConfig(Stats::StatName stat_prefix, Server::Configuration::FactoryContext& context,
229
               ShadowWriterPtr&& shadow_writer,
230
               const envoy::extensions::filters::http::router::v3::Router& config);
231
232
  bool createFilterChain(
233
      Http::FilterChainManager& manager, bool only_create_if_configured = false,
234
2.40k
      const Http::FilterChainOptions& options = Http::EmptyFilterChainOptions{}) const override {
235
    // Currently there is no default filter chain, so only_create_if_configured true doesn't make
236
    // sense.
237
2.40k
    ASSERT(!only_create_if_configured);
238
2.40k
    if (upstream_http_filter_factories_.empty()) {
239
2.40k
      return false;
240
2.40k
    }
241
0
    Http::FilterChainUtility::createFilterChainForFactories(manager, options,
242
0
                                                            upstream_http_filter_factories_);
243
0
    return true;
244
2.40k
  }
245
246
  bool createUpgradeFilterChain(absl::string_view, const UpgradeMap*,
247
0
                                Http::FilterChainManager&) const override {
248
    // Upgrade filter chains not yet supported for upstream HTTP filters.
249
0
    return false;
250
0
  }
251
252
  using HeaderVector = std::vector<Http::LowerCaseString>;
253
  using HeaderVectorPtr = std::unique_ptr<HeaderVector>;
254
255
0
  ShadowWriter& shadowWriter() { return *shadow_writer_; }
256
2.40k
  TimeSource& timeSource() { return time_source_; }
257
258
  Router::Context& router_context_;
259
  Stats::Scope& scope_;
260
  const LocalInfo::LocalInfo& local_info_;
261
  Upstream::ClusterManager& cm_;
262
  Runtime::Loader& runtime_;
263
  FilterStats default_stats_;
264
  FilterStats async_stats_;
265
  Random::RandomGenerator& random_;
266
  const bool emit_dynamic_stats_;
267
  const bool start_child_span_;
268
  const bool suppress_envoy_headers_;
269
  const bool respect_expected_rq_timeout_;
270
  const bool suppress_grpc_request_failure_code_stats_;
271
  // TODO(xyu-stripe): Make this a bitset to keep cluster memory footprint down.
272
  HeaderVectorPtr strict_check_headers_;
273
  const bool flush_upstream_log_on_upstream_stream_;
274
  absl::optional<std::chrono::milliseconds> upstream_log_flush_interval_;
275
  std::list<AccessLog::InstanceSharedPtr> upstream_logs_;
276
  Http::Context& http_context_;
277
  Stats::StatName zone_name_;
278
  Stats::StatName empty_stat_name_;
279
  std::unique_ptr<Server::Configuration::UpstreamFactoryContext> upstream_ctx_;
280
  Http::FilterChainUtility::FilterFactoriesList upstream_http_filter_factories_;
281
282
private:
283
  ShadowWriterPtr shadow_writer_;
284
  TimeSource& time_source_;
285
};
286
287
using FilterConfigSharedPtr = std::shared_ptr<FilterConfig>;
288
289
class UpstreamRequest;
290
using UpstreamRequestPtr = std::unique_ptr<UpstreamRequest>;
291
292
/**
293
 * Service routing filter.
294
 */
295
class Filter : Logger::Loggable<Logger::Id::router>,
296
               public Http::StreamDecoderFilter,
297
               public Upstream::LoadBalancerContextBase,
298
               public RouterFilterInterface {
299
public:
300
  Filter(FilterConfig& config, FilterStats& stats)
301
      : config_(config), stats_(stats), grpc_request_(false), exclude_http_code_stats_(false),
302
        downstream_response_started_(false), downstream_end_stream_(false), is_retry_(false),
303
        request_buffer_overflowed_(false), streaming_shadows_(Runtime::runtimeFeatureEnabled(
304
2.88k
                                               "envoy.reloadable_features.streaming_shadow")) {}
305
306
  ~Filter() override;
307
308
  static StreamInfo::ResponseFlag
309
  streamResetReasonToResponseFlag(Http::StreamResetReason reset_reason);
310
311
  // Http::StreamFilterBase
312
  void onDestroy() override;
313
314
  // Http::StreamDecoderFilter
315
  Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& headers,
316
                                          bool end_stream) override;
317
  Http::FilterDataStatus decodeData(Buffer::Instance& data, bool end_stream) override;
318
  Http::FilterTrailersStatus decodeTrailers(Http::RequestTrailerMap& trailers) override;
319
  Http::FilterMetadataStatus decodeMetadata(Http::MetadataMap& metadata_map) override;
320
  void setDecoderFilterCallbacks(Http::StreamDecoderFilterCallbacks& callbacks) override;
321
322
  // Upstream::LoadBalancerContext
323
0
  absl::optional<uint64_t> computeHashKey() override {
324
0
    if (route_entry_ && downstream_headers_) {
325
0
      auto hash_policy = route_entry_->hashPolicy();
326
0
      if (hash_policy) {
327
0
        return hash_policy->generateHash(
328
0
            callbacks_->streamInfo().downstreamAddressProvider().remoteAddress().get(),
329
0
            *downstream_headers_,
330
0
            [this](const std::string& key, const std::string& path, std::chrono::seconds max_age,
331
0
                   Http::CookieAttributeRefVector attributes) {
332
0
              return addDownstreamSetCookie(key, path, max_age, attributes);
333
0
            },
334
0
            callbacks_->streamInfo().filterState());
335
0
      }
336
0
    }
337
0
    return {};
338
0
  }
339
0
  const Router::MetadataMatchCriteria* metadataMatchCriteria() override {
340
0
    if (route_entry_) {
341
      // Have we been called before? If so, there's no need to recompute because
342
      // by the time this method is called for the first time, route_entry_ should
343
      // not change anymore.
344
0
      if (metadata_match_ != nullptr) {
345
0
        return metadata_match_.get();
346
0
      }
347
348
      // The request's metadata, if present, takes precedence over the route's.
349
0
      const auto& request_metadata = callbacks_->streamInfo().dynamicMetadata().filter_metadata();
350
0
      const auto filter_it = request_metadata.find(Envoy::Config::MetadataFilters::get().ENVOY_LB);
351
0
      if (filter_it != request_metadata.end()) {
352
0
        if (route_entry_->metadataMatchCriteria() != nullptr) {
353
0
          metadata_match_ =
354
0
              route_entry_->metadataMatchCriteria()->mergeMatchCriteria(filter_it->second);
355
0
        } else {
356
0
          metadata_match_ = std::make_unique<Router::MetadataMatchCriteriaImpl>(filter_it->second);
357
0
        }
358
0
        return metadata_match_.get();
359
0
      }
360
0
      return route_entry_->metadataMatchCriteria();
361
0
    }
362
0
    return nullptr;
363
0
  }
364
6.06k
  const Network::Connection* downstreamConnection() const override {
365
6.06k
    return callbacks_->connection().ptr();
366
6.06k
  }
367
0
  const StreamInfo::StreamInfo* requestStreamInfo() const override {
368
0
    return &callbacks_->streamInfo();
369
0
  }
370
0
  const Http::RequestHeaderMap* downstreamHeaders() const override { return downstream_headers_; }
371
372
2.39k
  bool shouldSelectAnotherHost(const Upstream::Host& host) override {
373
    // We only care about host selection when performing a retry, at which point we consult the
374
    // RetryState to see if we're configured to avoid certain hosts during retries.
375
2.39k
    if (!is_retry_) {
376
2.39k
      return false;
377
2.39k
    }
378
379
0
    ASSERT(retry_state_);
380
0
    return retry_state_->shouldSelectAnotherHost(host);
381
0
  }
382
383
  const Upstream::HealthyAndDegradedLoad& determinePriorityLoad(
384
      const Upstream::PrioritySet& priority_set,
385
      const Upstream::HealthyAndDegradedLoad& original_priority_load,
386
2.39k
      const Upstream::RetryPriority::PriorityMappingFunc& priority_mapping_func) override {
387
    // We only modify the priority load on retries.
388
2.39k
    if (!is_retry_) {
389
2.39k
      return original_priority_load;
390
2.39k
    }
391
0
    return retry_state_->priorityLoadForRetry(priority_set, original_priority_load,
392
0
                                              priority_mapping_func);
393
2.39k
  }
394
395
2.39k
  uint32_t hostSelectionRetryCount() const override {
396
2.39k
    if (!is_retry_) {
397
2.39k
      return 1;
398
2.39k
    }
399
0
    return retry_state_->hostSelectionMaxAttempts();
400
2.39k
  }
401
402
2.39k
  Network::Socket::OptionsSharedPtr upstreamSocketOptions() const override {
403
2.39k
    return (upstream_options_ != nullptr) ? upstream_options_
404
2.39k
                                          : callbacks_->getUpstreamSocketOptions();
405
2.39k
  }
406
407
4.38k
  Network::TransportSocketOptionsConstSharedPtr upstreamTransportSocketOptions() const override {
408
4.38k
    return transport_socket_options_;
409
4.38k
  }
410
411
2.39k
  absl::optional<OverrideHost> overrideHostToSelect() const override {
412
2.39k
    if (is_retry_) {
413
0
      return {};
414
0
    }
415
2.39k
    return callbacks_->upstreamOverrideHost();
416
2.39k
  }
417
418
  /**
419
   * Set a computed cookie to be sent with the downstream headers.
420
   * @param key supplies the size of the cookie
421
   * @param max_age the lifetime of the cookie
422
   * @param  path the path of the cookie, or ""
423
   * @return std::string the value of the new cookie
424
   */
425
  std::string addDownstreamSetCookie(const std::string& key, const std::string& path,
426
                                     std::chrono::seconds max_age,
427
0
                                     Http::CookieAttributeRefVector attributes) {
428
    // The cookie value should be the same per connection so that if multiple
429
    // streams race on the same path, they all receive the same cookie.
430
    // Since the downstream port is part of the hashed value, multiple HTTP1
431
    // connections can receive different cookies if they race on requests.
432
0
    std::string value;
433
0
    const Network::Connection* conn = downstreamConnection();
434
    // Need to check for null conn if this is ever used by Http::AsyncClient in the future.
435
0
    value = conn->connectionInfoProvider().remoteAddress()->asString() +
436
0
            conn->connectionInfoProvider().localAddress()->asString();
437
438
0
    const std::string cookie_value = Hex::uint64ToHex(HashUtil::xxHash64(value));
439
0
    downstream_set_cookies_.emplace_back(
440
0
        Http::Utility::makeSetCookieValue(key, cookie_value, path, max_age, true, attributes));
441
0
    return cookie_value;
442
0
  }
443
444
  // RouterFilterInterface
445
  void onUpstream1xxHeaders(Http::ResponseHeaderMapPtr&& headers,
446
                            UpstreamRequest& upstream_request) override;
447
  void onUpstreamHeaders(uint64_t response_code, Http::ResponseHeaderMapPtr&& headers,
448
                         UpstreamRequest& upstream_request, bool end_stream) override;
449
  void onUpstreamData(Buffer::Instance& data, UpstreamRequest& upstream_request,
450
                      bool end_stream) override;
451
  void onUpstreamTrailers(Http::ResponseTrailerMapPtr&& trailers,
452
                          UpstreamRequest& upstream_request) override;
453
  void onUpstreamMetadata(Http::MetadataMapPtr&& metadata_map) override;
454
  void onUpstreamReset(Http::StreamResetReason reset_reason, absl::string_view transport_failure,
455
                       UpstreamRequest& upstream_request) override;
456
  void onUpstreamHostSelected(Upstream::HostDescriptionConstSharedPtr host,
457
                              bool pool_success) override;
458
  void onPerTryTimeout(UpstreamRequest& upstream_request) override;
459
  void onPerTryIdleTimeout(UpstreamRequest& upstream_request) override;
460
  void onStreamMaxDurationReached(UpstreamRequest& upstream_request) override;
461
72.4k
  Http::StreamDecoderFilterCallbacks* callbacks() override { return callbacks_; }
462
15.0k
  Upstream::ClusterInfoConstSharedPtr cluster() override { return cluster_; }
463
12.8k
  FilterConfig& config() override { return config_; }
464
4.32k
  TimeoutData timeout() override { return timeout_; }
465
2.32k
  absl::optional<std::chrono::milliseconds> dynamicMaxStreamDuration() const override {
466
2.32k
    return dynamic_max_stream_duration_;
467
2.32k
  }
468
20.4k
  Http::RequestHeaderMap* downstreamHeaders() override { return downstream_headers_; }
469
12.9k
  Http::RequestTrailerMap* downstreamTrailers() override { return downstream_trailers_; }
470
1.89k
  bool downstreamResponseStarted() const override { return downstream_response_started_; }
471
2.32k
  bool downstreamEndStream() const override { return downstream_end_stream_; }
472
0
  uint32_t attemptCount() const override { return attempt_count_; }
473
0
  const std::list<UpstreamRequestPtr>& upstreamRequests() const { return upstream_requests_; }
474
475
0
  TimeSource& timeSource() { return config_.timeSource(); }
476
0
  const Route* route() const { return route_.get(); }
477
0
  const FilterStats& stats() { return stats_; }
478
479
protected:
480
0
  void setRetryShadowBufferLimit(uint32_t retry_shadow_buffer_limit) {
481
0
    ASSERT(retry_shadow_buffer_limit_ > retry_shadow_buffer_limit);
482
0
    retry_shadow_buffer_limit_ = retry_shadow_buffer_limit;
483
0
  }
484
485
private:
486
  friend class UpstreamRequest;
487
488
  enum class TimeoutRetry { Yes, No };
489
490
  void onPerTryTimeoutCommon(UpstreamRequest& upstream_request, Stats::Counter& error_counter,
491
                             const std::string& response_code_details);
492
  Stats::StatName upstreamZone(Upstream::HostDescriptionConstSharedPtr upstream_host);
493
  void chargeUpstreamCode(uint64_t response_status_code,
494
                          const Http::ResponseHeaderMap& response_headers,
495
                          Upstream::HostDescriptionConstSharedPtr upstream_host, bool dropped);
496
  void chargeUpstreamCode(Http::Code code, Upstream::HostDescriptionConstSharedPtr upstream_host,
497
                          bool dropped);
498
  void chargeUpstreamAbort(Http::Code code, bool dropped, UpstreamRequest& upstream_request);
499
  void cleanup();
500
  virtual RetryStatePtr
501
  createRetryState(const RetryPolicy& policy, Http::RequestHeaderMap& request_headers,
502
                   const Upstream::ClusterInfo& cluster, const VirtualCluster* vcluster,
503
                   RouteStatsContextOptRef route_stats_context, Runtime::Loader& runtime,
504
                   Random::RandomGenerator& random, Event::Dispatcher& dispatcher,
505
                   TimeSource& time_source, Upstream::ResourcePriority priority) PURE;
506
507
  std::unique_ptr<GenericConnPool>
508
  createConnPool(Upstream::ThreadLocalCluster& thread_local_cluster);
509
  UpstreamRequestPtr createUpstreamRequest();
510
  absl::optional<absl::string_view> getShadowCluster(const ShadowPolicy& shadow_policy,
511
                                                     const Http::HeaderMap& headers) const;
512
513
  void maybeDoShadowing();
514
  bool maybeRetryReset(Http::StreamResetReason reset_reason, UpstreamRequest& upstream_request,
515
                       TimeoutRetry is_timeout_retry);
516
  uint32_t numRequestsAwaitingHeaders();
517
  void onGlobalTimeout();
518
  void onRequestComplete();
519
  void onResponseTimeout();
520
  // Handle an upstream request aborted due to a local timeout.
521
  void onSoftPerTryTimeout();
522
  void onSoftPerTryTimeout(UpstreamRequest& upstream_request);
523
  void onUpstreamTimeoutAbort(StreamInfo::ResponseFlag response_flag, absl::string_view details);
524
  // Handle an "aborted" upstream request, meaning we didn't see response
525
  // headers (e.g. due to a reset). Handles recording stats and responding
526
  // downstream if appropriate.
527
  void onUpstreamAbort(Http::Code code, StreamInfo::ResponseFlag response_flag,
528
                       absl::string_view body, bool dropped, absl::string_view details);
529
  void onUpstreamComplete(UpstreamRequest& upstream_request);
530
  // Reset all in-flight upstream requests.
531
  void resetAll();
532
  // Reset all in-flight upstream requests that do NOT match the passed argument. This is used
533
  // if a "good" response comes back and we return downstream, so there is no point in waiting
534
  // for the remaining upstream requests to return.
535
  void resetOtherUpstreams(UpstreamRequest& upstream_request);
536
  void sendNoHealthyUpstreamResponse();
537
  bool setupRedirect(const Http::ResponseHeaderMap& headers);
538
  bool convertRequestHeadersForInternalRedirect(Http::RequestHeaderMap& downstream_headers,
539
                                                const Http::HeaderEntry& internal_redirect,
540
                                                uint64_t status_code);
541
  void updateOutlierDetection(Upstream::Outlier::Result result, UpstreamRequest& upstream_request,
542
                              absl::optional<uint64_t> code);
543
  void doRetry(bool can_send_early_data, bool can_use_http3, TimeoutRetry is_timeout_retry);
544
  void runRetryOptionsPredicates(UpstreamRequest& retriable_request);
545
  // Called immediately after a non-5xx header is received from upstream, performs stats accounting
546
  // and handle difference between gRPC and non-gRPC requests.
547
  void handleNon5xxResponseHeaders(absl::optional<Grpc::Status::GrpcStatus> grpc_status,
548
                                   UpstreamRequest& upstream_request, bool end_stream,
549
                                   uint64_t grpc_to_http_status);
550
3.36k
  Http::Context& httpContext() { return config_.http_context_; }
551
552
  RetryStatePtr retry_state_;
553
  FilterConfig& config_;
554
  Http::StreamDecoderFilterCallbacks* callbacks_{};
555
  RouteConstSharedPtr route_;
556
  const RouteEntry* route_entry_{};
557
  Upstream::ClusterInfoConstSharedPtr cluster_;
558
  std::unique_ptr<Stats::StatNameDynamicStorage> alt_stat_prefix_;
559
  const VirtualCluster* request_vcluster_{};
560
  RouteStatsContextOptRef route_stats_context_;
561
  Event::TimerPtr response_timeout_;
562
  TimeoutData timeout_;
563
  std::list<UpstreamRequestPtr> upstream_requests_;
564
  FilterStats stats_;
565
  // Tracks which upstream request "wins" and will have the corresponding
566
  // response forwarded downstream
567
  UpstreamRequest* final_upstream_request_ = nullptr;
568
  Http::RequestHeaderMap* downstream_headers_{};
569
  Http::RequestTrailerMap* downstream_trailers_{};
570
  MonotonicTime downstream_request_complete_time_;
571
  MetadataMatchCriteriaConstPtr metadata_match_;
572
  std::function<void(Http::ResponseHeaderMap&)> modify_headers_;
573
  std::vector<std::reference_wrapper<const ShadowPolicy>> active_shadow_policies_{};
574
  std::unique_ptr<Http::RequestHeaderMap> shadow_headers_;
575
  std::unique_ptr<Http::RequestTrailerMap> shadow_trailers_;
576
  // The stream lifetime configured by request header.
577
  absl::optional<std::chrono::milliseconds> dynamic_max_stream_duration_;
578
  // list of cookies to add to upstream headers
579
  std::vector<std::string> downstream_set_cookies_;
580
581
  Network::TransportSocketOptionsConstSharedPtr transport_socket_options_;
582
  Network::Socket::OptionsSharedPtr upstream_options_;
583
  // Set of ongoing shadow streams which have not yet received end stream.
584
  absl::flat_hash_set<Http::AsyncClient::OngoingRequest*> shadow_streams_;
585
586
  // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
587
  uint32_t retry_shadow_buffer_limit_{std::numeric_limits<uint32_t>::max()};
588
  uint32_t attempt_count_{1};
589
  uint32_t pending_retries_{0};
590
  Http::Code timeout_response_code_ = Http::Code::GatewayTimeout;
591
  FilterUtility::HedgingParams hedging_params_;
592
  bool grpc_request_ : 1;
593
  bool exclude_http_code_stats_ : 1;
594
  bool downstream_response_started_ : 1;
595
  bool downstream_end_stream_ : 1;
596
  bool is_retry_ : 1;
597
  bool include_attempt_count_in_request_ : 1;
598
  bool include_timeout_retry_header_in_request_ : 1;
599
  bool request_buffer_overflowed_ : 1;
600
  const bool streaming_shadows_ : 1;
601
};
602
603
class ProdFilter : public Filter {
604
public:
605
  using Filter::Filter;
606
607
private:
608
  // Filter
609
  RetryStatePtr createRetryState(const RetryPolicy& policy, Http::RequestHeaderMap& request_headers,
610
                                 const Upstream::ClusterInfo& cluster,
611
                                 const VirtualCluster* vcluster,
612
                                 RouteStatsContextOptRef route_stats_context,
613
                                 Runtime::Loader& runtime, Random::RandomGenerator& random,
614
                                 Event::Dispatcher& dispatcher, TimeSource& time_source,
615
                                 Upstream::ResourcePriority priority) override;
616
};
617
618
} // namespace Router
619
} // namespace Envoy