#pragma once #include #include #include #include #include #include "envoy/http/codec.h" #include "envoy/http/codes.h" #include "envoy/http/conn_pool.h" #include "envoy/http/filter.h" #include "envoy/stats/scope.h" #include "envoy/tcp/conn_pool.h" #include "common/buffer/watermark_buffer.h" #include "common/common/cleanup.h" #include "common/common/hash.h" #include "common/common/hex.h" #include "common/common/linked_object.h" #include "common/common/logger.h" #include "common/config/well_known_names.h" #include "common/stream_info/stream_info_impl.h" namespace Envoy { namespace Router { class GenericUpstream; class GenericConnectionPoolCallbacks; class RouterFilterInterface; class UpstreamRequest; // The base request for Upstream. class UpstreamRequest : public Logger::Loggable, public UpstreamToDownstream, public LinkedObject, public GenericConnectionPoolCallbacks { public: UpstreamRequest(RouterFilterInterface& parent, std::unique_ptr&& conn_pool); ~UpstreamRequest() override; void encodeHeaders(bool end_stream); void encodeData(Buffer::Instance& data, bool end_stream); void encodeTrailers(const Http::RequestTrailerMap& trailers); void encodeMetadata(Http::MetadataMapPtr&& metadata_map_ptr); void resetStream(); void setupPerTryTimeout(); void onPerTryTimeout(); void maybeEndDecode(bool end_stream); void onUpstreamHostSelected(Upstream::HostDescriptionConstSharedPtr host); // Http::StreamDecoder void decodeData(Buffer::Instance& data, bool end_stream) override; void decodeMetadata(Http::MetadataMapPtr&& metadata_map) override; // UpstreamToDownstream (Http::ResponseDecoder) void decode100ContinueHeaders(Http::ResponseHeaderMapPtr&& headers) override; void decodeHeaders(Http::ResponseHeaderMapPtr&& headers, bool end_stream) override; void decodeTrailers(Http::ResponseTrailerMapPtr&& trailers) override; // UpstreamToDownstream (Http::StreamCallbacks) void onResetStream(Http::StreamResetReason reason, absl::string_view transport_failure_reason) override; void onAboveWriteBufferHighWatermark() override { disableDataFromDownstreamForFlowControl(); } void onBelowWriteBufferLowWatermark() override { enableDataFromDownstreamForFlowControl(); } // UpstreamToDownstream const RouteEntry& routeEntry() const override; const Network::Connection& connection() const override; void disableDataFromDownstreamForFlowControl(); void enableDataFromDownstreamForFlowControl(); // GenericConnPool void onPoolFailure(ConnectionPool::PoolFailureReason reason, absl::string_view transport_failure_reason, Upstream::HostDescriptionConstSharedPtr host) override; void onPoolReady(std::unique_ptr&& upstream, Upstream::HostDescriptionConstSharedPtr host, const Network::Address::InstanceConstSharedPtr& upstream_local_address, const StreamInfo::StreamInfo& info, absl::optional protocol) override; UpstreamToDownstream& upstreamToDownstream() override { return *this; } void clearRequestEncoder(); void onStreamMaxDurationReached(); struct DownstreamWatermarkManager : public Http::DownstreamWatermarkCallbacks { DownstreamWatermarkManager(UpstreamRequest& parent) : parent_(parent) {} // Http::DownstreamWatermarkCallbacks void onBelowWriteBufferLowWatermark() override; void onAboveWriteBufferHighWatermark() override; UpstreamRequest& parent_; }; void readEnable(); void encodeBodyAndTrailers(); // Getters and setters Upstream::HostDescriptionConstSharedPtr& upstreamHost() { return upstream_host_; } void outlierDetectionTimeoutRecorded(bool recorded) { outlier_detection_timeout_recorded_ = recorded; } bool outlierDetectionTimeoutRecorded() { return outlier_detection_timeout_recorded_; } const StreamInfo::UpstreamTiming& upstreamTiming() { return upstream_timing_; } void retried(bool value) { retried_ = value; } bool retried() { return retried_; } bool grpcRqSuccessDeferred() { return grpc_rq_success_deferred_; } void grpcRqSuccessDeferred(bool deferred) { grpc_rq_success_deferred_ = deferred; } void upstreamCanary(bool value) { upstream_canary_ = value; } bool upstreamCanary() { return upstream_canary_; } bool awaitingHeaders() { return awaiting_headers_; } void recordTimeoutBudget(bool value) { record_timeout_budget_ = value; } bool createPerTryTimeoutOnRequestComplete() { return create_per_try_timeout_on_request_complete_; } bool encodeComplete() const { return encode_complete_; } RouterFilterInterface& parent() { return parent_; } private: bool shouldSendEndStream() { // Only encode end stream if the full request has been received, the body // has been sent, and any trailers or metadata have also been sent. return encode_complete_ && !buffered_request_body_ && !encode_trailers_ && downstream_metadata_map_vector_.empty(); } RouterFilterInterface& parent_; std::unique_ptr conn_pool_; bool grpc_rq_success_deferred_; Event::TimerPtr per_try_timeout_; std::unique_ptr upstream_; absl::optional deferred_reset_reason_; Buffer::WatermarkBufferPtr buffered_request_body_; Upstream::HostDescriptionConstSharedPtr upstream_host_; DownstreamWatermarkManager downstream_watermark_manager_{*this}; Tracing::SpanPtr span_; StreamInfo::StreamInfoImpl stream_info_; StreamInfo::UpstreamTiming upstream_timing_; const MonotonicTime start_time_; // Copies of upstream headers/trailers. These are only set if upstream // access logging is configured. Http::ResponseHeaderMapPtr upstream_headers_; Http::ResponseTrailerMapPtr upstream_trailers_; Http::MetadataMapVector downstream_metadata_map_vector_; // Tracks the number of times the flow of data from downstream has been disabled. uint32_t downstream_data_disabled_{}; bool calling_encode_headers_ : 1; bool upstream_canary_ : 1; bool decode_complete_ : 1; bool encode_complete_ : 1; bool encode_trailers_ : 1; bool retried_ : 1; bool awaiting_headers_ : 1; bool outlier_detection_timeout_recorded_ : 1; // Tracks whether we deferred a per try timeout because the downstream request // had not been completed yet. bool create_per_try_timeout_on_request_complete_ : 1; // True if the CONNECT headers have been sent but proxying payload is paused // waiting for response headers. bool paused_for_connect_ : 1; // Sentinel to indicate if timeout budget tracking is configured for the cluster, // and if so, if the per-try histogram should record a value. bool record_timeout_budget_ : 1; Event::TimerPtr max_stream_duration_timer_; }; } // namespace Router } // namespace Envoy