in source/common/router/router.cc [206:337]
Http::FilterHeadersStatus Filter::decodeHeaders(Http::HeaderMap& headers, bool end_stream) {
// Do a common header check. We make sure that all outgoing requests have all HTTP/2 headers.
// These get stripped by HTTP/1 codec where applicable.
ASSERT(headers.Path());
ASSERT(headers.Method());
ASSERT(headers.Host());
downstream_headers_ = &headers;
// TODO: Maybe add a filter API for this.
grpc_request_ = Grpc::Common::hasGrpcContentType(headers);
// Only increment rq total stat if we actually decode headers here. This does not count requests
// that get handled by earlier filters.
config_.stats_.rq_total_.inc();
// Determine if there is a route entry or a direct response for the request.
route_ = callbacks_->route();
if (!route_) {
config_.stats_.no_route_.inc();
ENVOY_STREAM_LOG(debug, "no cluster match for URL '{}'", *callbacks_,
headers.Path()->value().c_str());
callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound);
callbacks_->sendLocalReply(Http::Code::NotFound, "", nullptr, absl::nullopt);
return Http::FilterHeadersStatus::StopIteration;
}
// Determine if there is a direct response for the request.
const auto* direct_response = route_->directResponseEntry();
if (direct_response != nullptr) {
config_.stats_.rq_direct_response_.inc();
direct_response->rewritePathHeader(headers, !config_.suppress_envoy_headers_);
callbacks_->sendLocalReply(
direct_response->responseCode(), direct_response->responseBody(),
[this, direct_response,
&request_headers = headers](Http::HeaderMap& response_headers) -> void {
const auto new_path = direct_response->newPath(request_headers);
if (!new_path.empty()) {
response_headers.addReferenceKey(Http::Headers::get().Location, new_path);
}
direct_response->finalizeResponseHeaders(response_headers, callbacks_->streamInfo());
},
absl::nullopt);
return Http::FilterHeadersStatus::StopIteration;
}
// A route entry matches for the request.
route_entry_ = route_->routeEntry();
Upstream::ThreadLocalCluster* cluster = config_.cm_.get(route_entry_->clusterName());
if (!cluster) {
config_.stats_.no_cluster_.inc();
ENVOY_STREAM_LOG(debug, "unknown cluster '{}'", *callbacks_, route_entry_->clusterName());
callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound);
callbacks_->sendLocalReply(route_entry_->clusterNotFoundResponseCode(), "", nullptr,
absl::nullopt);
return Http::FilterHeadersStatus::StopIteration;
}
cluster_ = cluster->info();
// Set up stat prefixes, etc.
request_vcluster_ = route_entry_->virtualCluster(headers);
ENVOY_STREAM_LOG(debug, "cluster '{}' match for URL '{}'", *callbacks_,
route_entry_->clusterName(), headers.Path()->value().c_str());
const Http::HeaderEntry* request_alt_name = headers.EnvoyUpstreamAltStatName();
if (request_alt_name) {
alt_stat_prefix_ = std::string(request_alt_name->value().c_str()) + ".";
headers.removeEnvoyUpstreamAltStatName();
}
// See if we are supposed to immediately kill some percentage of this cluster's traffic.
if (cluster_->maintenanceMode()) {
callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::UpstreamOverflow);
chargeUpstreamCode(Http::Code::ServiceUnavailable, nullptr, true);
callbacks_->sendLocalReply(Http::Code::ServiceUnavailable, "maintenance mode",
[this](Http::HeaderMap& headers) {
if (!config_.suppress_envoy_headers_) {
headers.insertEnvoyOverloaded().value(
Http::Headers::get().EnvoyOverloadedValues.True);
}
},
absl::nullopt);
cluster_->stats().upstream_rq_maintenance_mode_.inc();
return Http::FilterHeadersStatus::StopIteration;
}
// Fetch a connection pool for the upstream cluster.
Http::ConnectionPool::Instance* conn_pool = getConnPool();
if (!conn_pool) {
sendNoHealthyUpstreamResponse();
return Http::FilterHeadersStatus::StopIteration;
}
timeout_ = FilterUtility::finalTimeout(*route_entry_, headers, !config_.suppress_envoy_headers_,
grpc_request_);
// If this header is set with any value, use an alternate response code on timeout
if (headers.EnvoyUpstreamRequestTimeoutAltResponse()) {
timeout_response_code_ = Http::Code::NoContent;
headers.removeEnvoyUpstreamRequestTimeoutAltResponse();
}
include_attempt_count_ = route_entry_->includeAttemptCount();
if (include_attempt_count_) {
headers.insertEnvoyAttemptCount().value(attempt_count_);
}
route_entry_->finalizeRequestHeaders(headers, callbacks_->streamInfo(),
!config_.suppress_envoy_headers_);
FilterUtility::setUpstreamScheme(headers, *cluster_);
// Ensure an http transport scheme is selected before continuing with decoding.
ASSERT(headers.Scheme());
retry_state_ =
createRetryState(route_entry_->retryPolicy(), headers, *cluster_, config_.runtime_,
config_.random_, callbacks_->dispatcher(), route_entry_->priority());
do_shadowing_ = FilterUtility::shouldShadow(route_entry_->shadowPolicy(), config_.runtime_,
callbacks_->streamId());
ENVOY_STREAM_LOG(debug, "router decoding headers:\n{}", *callbacks_, headers);
upstream_request_ = std::make_unique<UpstreamRequest>(*this, *conn_pool);
upstream_request_->encodeHeaders(end_stream);
if (end_stream) {
onRequestComplete();
}
return Http::FilterHeadersStatus::StopIteration;
}