in source/common/http/conn_manager_impl.cc [1104:1243]
void ConnectionManagerImpl::ActiveStream::encodeHeaders(ActiveStreamEncoderFilter* filter,
HeaderMap& headers, bool end_stream) {
resetIdleTimer();
disarmRequestTimeout();
std::list<ActiveStreamEncoderFilterPtr>::iterator entry = commonEncodePrefix(filter, end_stream);
std::list<ActiveStreamEncoderFilterPtr>::iterator continue_data_entry = encoder_filters_.end();
for (; entry != encoder_filters_.end(); entry++) {
ASSERT(!(state_.filter_call_state_ & FilterCallState::EncodeHeaders));
state_.filter_call_state_ |= FilterCallState::EncodeHeaders;
(*entry)->end_stream_ =
encoding_headers_only_ || (end_stream && continue_data_entry == encoder_filters_.end());
FilterHeadersStatus status = (*entry)->handle_->encodeHeaders(headers, (*entry)->end_stream_);
state_.filter_call_state_ &= ~FilterCallState::EncodeHeaders;
ENVOY_STREAM_LOG(trace, "encode headers called: filter={} status={}", *this,
static_cast<const void*>((*entry).get()), static_cast<uint64_t>(status));
const auto continue_iteration =
(*entry)->commonHandleAfterHeadersCallback(status, encoding_headers_only_);
// If we're encoding a headers only response, then mark the local as complete. This ensures
// that we don't attempt to reset the downstream request in doEndStream.
if (encoding_headers_only_) {
state_.local_complete_ = true;
}
if (!continue_iteration) {
return;
}
// Here we handle the case where we have a header only response, but a filter adds a body
// to it. We need to not raise end_stream = true to further filters during inline iteration.
if (end_stream && buffered_response_data_ && continue_data_entry == encoder_filters_.end()) {
continue_data_entry = entry;
}
}
// Base headers.
connection_manager_.config_.dateProvider().setDateHeader(headers);
// Following setReference() is safe because serverName() is constant for the life of the listener.
headers.insertServer().value().setReference(connection_manager_.config_.serverName());
ConnectionManagerUtility::mutateResponseHeaders(headers, request_headers_.get(),
connection_manager_.config_.via());
// See if we want to drain/close the connection. Send the go away frame prior to encoding the
// header block.
if (connection_manager_.drain_state_ == DrainState::NotDraining &&
connection_manager_.drain_close_.drainClose()) {
// This doesn't really do anything for HTTP/1.1 other then give the connection another boost
// of time to race with incoming requests. It mainly just keeps the logic the same between
// HTTP/1.1 and HTTP/2.
connection_manager_.startDrainSequence();
connection_manager_.stats_.named_.downstream_cx_drain_close_.inc();
ENVOY_STREAM_LOG(debug, "drain closing connection", *this);
}
if (connection_manager_.drain_state_ == DrainState::NotDraining && state_.saw_connection_close_) {
ENVOY_STREAM_LOG(debug, "closing connection due to connection close header", *this);
connection_manager_.drain_state_ = DrainState::Closing;
}
if (connection_manager_.drain_state_ == DrainState::NotDraining &&
connection_manager_.overload_disable_keepalive_ref_ == Server::OverloadActionState::Active) {
ENVOY_STREAM_LOG(debug, "disabling keepalive due to envoy overload", *this);
connection_manager_.drain_state_ = DrainState::Closing;
connection_manager_.stats_.named_.downstream_cx_overload_disable_keepalive_.inc();
}
// If we are destroying a stream before remote is complete and the connection does not support
// multiplexing, we should disconnect since we don't want to wait around for the request to
// finish.
if (!state_.remote_complete_) {
if (connection_manager_.codec_->protocol() != Protocol::Http2) {
connection_manager_.drain_state_ = DrainState::Closing;
}
connection_manager_.stats_.named_.downstream_rq_response_before_rq_complete_.inc();
}
if (connection_manager_.drain_state_ == DrainState::Closing &&
connection_manager_.codec_->protocol() != Protocol::Http2) {
// If the connection manager is draining send "Connection: Close" on HTTP/1.1 connections.
// Do not do this for H2 (which drains via GOAWAY) or Upgrade (as the upgrade
// payload is no longer HTTP/1.1)
if (!Utility::isUpgrade(headers)) {
headers.insertConnection().value().setReference(Headers::get().ConnectionValues.Close);
}
}
if (connection_manager_.config_.tracingConfig()) {
if (connection_manager_.config_.tracingConfig()->operation_name_ ==
Tracing::OperationName::Ingress) {
// For ingress (inbound) responses, if the request headers do not include a
// decorator operation (override), then pass the decorator's operation name (if defined)
// as a response header to enable the client service to use it in its client span.
if (decorated_operation_) {
headers.insertEnvoyDecoratorOperation().value(*decorated_operation_);
}
} else if (connection_manager_.config_.tracingConfig()->operation_name_ ==
Tracing::OperationName::Egress) {
const HeaderEntry* resp_operation_override = headers.EnvoyDecoratorOperation();
// For Egress (outbound) response, if a decorator operation name has been provided, it
// should be used to override the active span's operation.
if (resp_operation_override) {
if (!resp_operation_override->value().empty() && active_span_) {
active_span_->setOperation(resp_operation_override->value().c_str());
}
// Remove header so not propagated to service.
headers.removeEnvoyDecoratorOperation();
}
}
}
chargeStats(headers);
ENVOY_STREAM_LOG(debug, "encoding headers via codec (end_stream={}):\n{}", *this,
encoding_headers_only_ ||
(end_stream && continue_data_entry == encoder_filters_.end()),
headers);
// Now actually encode via the codec.
stream_info_.onFirstDownstreamTxByteSent();
response_encoder_->encodeHeaders(
headers,
encoding_headers_only_ || (end_stream && continue_data_entry == encoder_filters_.end()));
if (continue_data_entry != encoder_filters_.end()) {
// We use the continueEncoding() code since it will correctly handle not calling
// encodeHeaders() again. Fake setting stopped_ since the continueEncoding() code expects it.
ASSERT(buffered_response_data_);
(*continue_data_entry)->stopped_ = true;
(*continue_data_entry)->continueEncoding();
} else {
// End encoding if this is a header only response, either due to a filter converting it to one
// or due to the upstream returning headers only.
maybeEndEncode(encoding_headers_only_ || end_stream);
}
}