Coverage Report

Created: 2024-09-19 09:45

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