uint32_t getLength(const Buffer::Instance* instance) { return instance ? instance->length() : 0; }
FilterConfig::create(Stats::StatName stat_prefix, Server::Configuration::FactoryContext& context,
upstream_log_flush_interval_ = std::chrono::milliseconds(DurationUtil::durationToMilliseconds(
return static_cast<uint64_t>(response_time.count() * TimeoutPrecisionFactor / timeout.count());
const Http::HeaderEntry* header_timeout_entry = request_headers.EnvoyUpstreamRequestTimeoutMs();
if (timeout.per_try_timeout_ >= timeout.global_timeout_ && timeout.global_timeout_.count() != 0) {
setTimeoutHeaders(0, timeout, route, request_headers, insert_envoy_expected_request_timeout_ms,
Stats::StatName Filter::upstreamZone(Upstream::HostDescriptionOptConstRef upstream_host) {
const bool is_canary = (upstream_canary_header && upstream_canary_header->value() == "true") ||
const bool internal_request = Http::HeaderUtility::isEnvoyInternalRequest(*downstream_headers_);
void Filter::chargeUpstreamCode(Http::Code code, Upstream::HostDescriptionOptConstRef upstream_host,
Http::FilterHeadersStatus Filter::decodeHeaders(Http::RequestHeaderMap& headers, bool end_stream) {
// Initialize the `modify_headers_` function that will be used to modify the response headers for
exclude_http_code_stats_ = grpc_request_ && config_->suppress_grpc_request_failure_code_stats_;
// Only increment rq total stat if we actually decode headers here. This does not count requests
ENVOY_STREAM_LOG(debug, "no route match for URL '{}'", *callbacks_, headers.getPathValue());
timeout_ = FilterUtility::finalTimeout(*route_entry_, headers, !config_->suppress_envoy_headers_,
// Finalize request headers (host/path rewriting + request_headers_to_add) before host selection.
const Formatter::Context formatter_context(&headers, {}, {}, {}, {}, &callbacks_->activeSpan());
route_entry_->finalizeRequestHeaders(headers, formatter_context, callbacks_->streamInfo(),
if (const auto& override_header = upstream_http_protocol_options->override_auto_sni_header();
if (auto downstream_connection = downstreamConnection(); downstream_connection != nullptr) {
continueDecodeHeaders(cluster, headers, end_stream, std::move(host_selection_response.host),
// Latch the cancel handle and call it in Filter::onDestroy to avoid any use-after-frees for cases
// When asynchronous host selection is complete, call the pre-configured on_host_selected_function.
void Filter::onAsyncHostSelection(Upstream::HostConstSharedPtr&& host, std::string&& details) {
ENVOY_STREAM_LOG(debug, "Completing asynchronous host selection [{}]\n", *callbacks_, details);
"envoy.router.host_selection_end_ms", callbacks_->dispatcher().timeSource().monotonicTime());
std::unique_ptr<GenericConnPool> generic_conn_pool = createConnPool(*cluster, selected_host);
callbacks_->sendLocalReply(Http::Code::ServiceUnavailable, "envoy overloaded", modify_headers_,
retry_state_ = createRetryState(*getEffectiveRetryPolicy(), headers, *cluster_, request_vcluster_,
!cluster_shadow_policies.empty() ? cluster_shadow_policies : route_entry_->shadowPolicies();
include_timeout_retry_header_in_request_ = route_->virtualHost()->includeIsTimeoutRetryHeader();
return factory->createGenericConnPool(host, cluster, upstream_protocol, route_entry_->priority(),
callbacks_->sendLocalReply(Http::Code::ServiceUnavailable, "no healthy upstream", modify_headers_,
const bool redirect_enabled = route_entry_ && route_entry_->internalRedirectPolicy().enabled();
if (would_exceed_buffer && retry_enabled && !is_redirect_only && !request_buffer_overflowed_) {
Http::MetadataMapPtr metadata_map_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
onPerTryTimeoutCommon(upstream_request, cluster_->trafficStats()->upstream_rq_per_try_timeout_,
void Filter::onPerTryTimeoutCommon(UpstreamRequest& upstream_request, Stats::Counter& error_counter,
if (maybeRetryReset(Http::StreamResetReason::LocalReset, upstream_request, TimeoutRetry::Yes)) {
if (maybeRetryReset(Http::StreamResetReason::LocalReset, upstream_request, TimeoutRetry::No)) {
void Filter::chargeUpstreamAbort(Http::Code code, bool dropped, UpstreamRequest& upstream_request) {
std::chrono::milliseconds response_time = std::chrono::duration_cast<std::chrono::milliseconds>(
// If we have not yet sent anything downstream, send a response with an appropriate status code.
// If the current request in this router has sent data to the upstream, we consider the request
[this, can_send_early_data = upstream_request.upstreamStreamOptions().can_send_early_data_,
updateOutlierDetection(Upstream::Outlier::Result::LocalOriginConnectFailed, upstream_request,
const StreamInfo::CoreResponseFlag response_flags = streamResetReasonToResponseFlag(reset_reason);
transport_failure_reason.empty() ? "" : absl::StrCat("|", transport_failure_reason), "}"));
// callback. Hence, the upstream request increases the virtual cluster's upstream_rq_total_ stat
ENVOY_STREAM_LOG(debug, "upstream headers complete: end_stream={}", *callbacks_, end_stream);
Upstream::Outlier::Result::ExtOriginRequestSuccess, response_code_for_outlier_detection);
handleNon5xxResponseHeaders(grpc_status, upstream_request, end_stream, grpc_to_http_status);
callbacks_->streamInfo().setUpstreamInfo(final_upstream_request_->streamInfo().upstreamInfo());
const Formatter::Context formatter_context(downstream_headers_, headers.get(), {}, {}, {},
route_entry_->finalizeResponseHeaders(*headers, formatter_context, callbacks_->streamInfo());
absl::optional<Grpc::Status::GrpcStatus> grpc_status = Grpc::Common::getGrpcStatus(*trailers);
std::chrono::milliseconds response_time = std::chrono::duration_cast<std::chrono::milliseconds>(
const bool internal_request = Http::HeaderUtility::isEnvoyInternalRequest(*downstream_headers_);
callbacks_->dispatcher().deferredDelete(upstream_request.removeFromList(upstream_requests_));
if (downstream_end_stream_ && (!request_buffer_overflowed_ || !callbacks_->decodingBuffer()) &&
ENVOY_STREAM_LOG(trace, "Internal redirect failed: no path in downstream_headers", *callbacks_);
const StreamInfo::FilterStateSharedPtr& filter_state = callbacks_->streamInfo().filterState();
std::unique_ptr<Http::RequestHeaderMapImpl> saved_headers = Http::RequestHeaderMapImpl::create();
if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.http_reject_path_with_fragment")) {
// contains #fragment. However the Location header is allowed to have #fragment in URI path. To
for (const auto& options_predicate : getEffectiveRetryPolicy()->retryOptionsPredicates()) {
void Filter::doRetry(bool can_send_early_data, bool can_use_http3, TimeoutRetry is_timeout_retry) {
"envoy.router.host_selection_end_ms", callbacks_->dispatcher().timeSource().monotonicTime());
if (!upstream_requests_.empty() && (upstream_requests_.front().get() == upstream_request_tmp)) {
ENVOY_STREAM_LOG(debug, "Router filter: cluster DROP_OVERLOAD configuration: {}", *callbacks_,
ASSERT(upstream_host.has_value(), "upstream host is not available for upstream request");
ProdFilter::createRetryState(const RetryPolicy& policy, Http::RequestHeaderMap& request_headers,
// Since doing retry will make Envoy to buffer the request body, if upstream using HTTP/3 is the