Line data Source code
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 175 : shadow_writer_(std::move(shadow_writer)), time_source_(time_source) {
220 175 : if (!strict_check_headers.empty()) {
221 2 : strict_check_headers_ = std::make_unique<HeaderVector>();
222 2 : for (const auto& header : strict_check_headers) {
223 2 : strict_check_headers_->emplace_back(Http::LowerCaseString(header));
224 2 : }
225 2 : }
226 175 : }
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 251 : 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 251 : ASSERT(!only_create_if_configured);
238 251 : if (upstream_http_filter_factories_.empty()) {
239 251 : return false;
240 251 : }
241 0 : Http::FilterChainUtility::createFilterChainForFactories(manager, options,
242 0 : upstream_http_filter_factories_);
243 0 : return true;
244 251 : }
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 251 : 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 545 : "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 685 : const Network::Connection* downstreamConnection() const override {
365 685 : return callbacks_->connection().ptr();
366 685 : }
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 251 : 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 251 : if (!is_retry_) {
376 251 : return false;
377 251 : }
378 :
379 0 : ASSERT(retry_state_);
380 0 : return retry_state_->shouldSelectAnotherHost(host);
381 251 : }
382 :
383 : const Upstream::HealthyAndDegradedLoad& determinePriorityLoad(
384 : const Upstream::PrioritySet& priority_set,
385 : const Upstream::HealthyAndDegradedLoad& original_priority_load,
386 251 : const Upstream::RetryPriority::PriorityMappingFunc& priority_mapping_func) override {
387 : // We only modify the priority load on retries.
388 251 : if (!is_retry_) {
389 251 : return original_priority_load;
390 251 : }
391 0 : return retry_state_->priorityLoadForRetry(priority_set, original_priority_load,
392 0 : priority_mapping_func);
393 251 : }
394 :
395 251 : uint32_t hostSelectionRetryCount() const override {
396 251 : if (!is_retry_) {
397 251 : return 1;
398 251 : }
399 0 : return retry_state_->hostSelectionMaxAttempts();
400 251 : }
401 :
402 251 : Network::Socket::OptionsSharedPtr upstreamSocketOptions() const override {
403 251 : return (upstream_options_ != nullptr) ? upstream_options_
404 251 : : callbacks_->getUpstreamSocketOptions();
405 251 : }
406 :
407 574 : Network::TransportSocketOptionsConstSharedPtr upstreamTransportSocketOptions() const override {
408 574 : return transport_socket_options_;
409 574 : }
410 :
411 502 : absl::optional<OverrideHost> overrideHostToSelect() const override {
412 502 : if (is_retry_) {
413 0 : return {};
414 0 : }
415 502 : return callbacks_->upstreamOverrideHost();
416 502 : }
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 7035 : Http::StreamDecoderFilterCallbacks* callbacks() override { return callbacks_; }
462 1385 : Upstream::ClusterInfoConstSharedPtr cluster() override { return cluster_; }
463 1170 : FilterConfig& config() override { return config_; }
464 294 : TimeoutData timeout() override { return timeout_; }
465 202 : absl::optional<std::chrono::milliseconds> dynamicMaxStreamDuration() const override {
466 202 : return dynamic_max_stream_duration_;
467 202 : }
468 2083 : Http::RequestHeaderMap* downstreamHeaders() override { return downstream_headers_; }
469 1436 : Http::RequestTrailerMap* downstreamTrailers() override { return downstream_trailers_; }
470 16 : bool downstreamResponseStarted() const override { return downstream_response_started_; }
471 202 : 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::ResponseHeaderMap& upstream_headers,
540 : const Http::HeaderEntry& internal_redirect,
541 : uint64_t status_code);
542 : void updateOutlierDetection(Upstream::Outlier::Result result, UpstreamRequest& upstream_request,
543 : absl::optional<uint64_t> code);
544 : void doRetry(bool can_send_early_data, bool can_use_http3, TimeoutRetry is_timeout_retry);
545 : void runRetryOptionsPredicates(UpstreamRequest& retriable_request);
546 : // Called immediately after a non-5xx header is received from upstream, performs stats accounting
547 : // and handle difference between gRPC and non-gRPC requests.
548 : void handleNon5xxResponseHeaders(absl::optional<Grpc::Status::GrpcStatus> grpc_status,
549 : UpstreamRequest& upstream_request, bool end_stream,
550 : uint64_t grpc_to_http_status);
551 272 : Http::Context& httpContext() { return config_.http_context_; }
552 : bool checkDropOverload(Upstream::ThreadLocalCluster& cluster,
553 : std::function<void(Http::ResponseHeaderMap&)>& modify_headers);
554 :
555 : RetryStatePtr retry_state_;
556 : FilterConfig& config_;
557 : Http::StreamDecoderFilterCallbacks* callbacks_{};
558 : RouteConstSharedPtr route_;
559 : const RouteEntry* route_entry_{};
560 : Upstream::ClusterInfoConstSharedPtr cluster_;
561 : std::unique_ptr<Stats::StatNameDynamicStorage> alt_stat_prefix_;
562 : const VirtualCluster* request_vcluster_{};
563 : RouteStatsContextOptRef route_stats_context_;
564 : Event::TimerPtr response_timeout_;
565 : TimeoutData timeout_;
566 : std::list<UpstreamRequestPtr> upstream_requests_;
567 : FilterStats stats_;
568 : // Tracks which upstream request "wins" and will have the corresponding
569 : // response forwarded downstream
570 : UpstreamRequest* final_upstream_request_ = nullptr;
571 : Http::RequestHeaderMap* downstream_headers_{};
572 : Http::RequestTrailerMap* downstream_trailers_{};
573 : MonotonicTime downstream_request_complete_time_;
574 : MetadataMatchCriteriaConstPtr metadata_match_;
575 : std::function<void(Http::ResponseHeaderMap&)> modify_headers_;
576 : std::vector<std::reference_wrapper<const ShadowPolicy>> active_shadow_policies_{};
577 : std::unique_ptr<Http::RequestHeaderMap> shadow_headers_;
578 : std::unique_ptr<Http::RequestTrailerMap> shadow_trailers_;
579 : // The stream lifetime configured by request header.
580 : absl::optional<std::chrono::milliseconds> dynamic_max_stream_duration_;
581 : // list of cookies to add to upstream headers
582 : std::vector<std::string> downstream_set_cookies_;
583 :
584 : Network::TransportSocketOptionsConstSharedPtr transport_socket_options_;
585 : Network::Socket::OptionsSharedPtr upstream_options_;
586 : // Set of ongoing shadow streams which have not yet received end stream.
587 : absl::flat_hash_set<Http::AsyncClient::OngoingRequest*> shadow_streams_;
588 :
589 : // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
590 : uint32_t retry_shadow_buffer_limit_{std::numeric_limits<uint32_t>::max()};
591 : uint32_t attempt_count_{1};
592 : uint32_t pending_retries_{0};
593 : Http::Code timeout_response_code_ = Http::Code::GatewayTimeout;
594 : FilterUtility::HedgingParams hedging_params_;
595 : bool grpc_request_ : 1;
596 : bool exclude_http_code_stats_ : 1;
597 : bool downstream_response_started_ : 1;
598 : bool downstream_end_stream_ : 1;
599 : bool is_retry_ : 1;
600 : bool include_attempt_count_in_request_ : 1;
601 : bool include_timeout_retry_header_in_request_ : 1;
602 : bool request_buffer_overflowed_ : 1;
603 : const bool streaming_shadows_ : 1;
604 : };
605 :
606 : class ProdFilter : public Filter {
607 : public:
608 : using Filter::Filter;
609 :
610 : private:
611 : // Filter
612 : RetryStatePtr createRetryState(const RetryPolicy& policy, Http::RequestHeaderMap& request_headers,
613 : const Upstream::ClusterInfo& cluster,
614 : const VirtualCluster* vcluster,
615 : RouteStatsContextOptRef route_stats_context,
616 : Runtime::Loader& runtime, Random::RandomGenerator& random,
617 : Event::Dispatcher& dispatcher, TimeSource& time_source,
618 : Upstream::ResourcePriority priority) override;
619 : };
620 :
621 : } // namespace Router
622 : } // namespace Envoy
|