void Filter::UpstreamRequest::onPoolReady(Http::StreamEncoder& request_encoder,
                                          Upstream::HostDescriptionConstSharedPtr host,
                                          const StreamInfo::StreamInfo& info) {
  // This may be called under an existing ScopeTrackerScopeState but it will unwind correctly.
  ScopeTrackerScopeState scope(&parent_.callbacks_->scope(), parent_.callbacks_->dispatcher());
  ENVOY_STREAM_LOG(debug, "pool ready", *parent_.callbacks_);

  host->outlierDetector().putResult(Upstream::Outlier::Result::LOCAL_ORIGIN_CONNECT_SUCCESS);

  // TODO(ggreenway): set upstream local address in the StreamInfo.
  onUpstreamHostSelected(host);
  request_encoder.getStream().addCallbacks(*this);

  stream_info_.setUpstreamSslConnection(info.downstreamSslConnection());
  parent_.callbacks_->streamInfo().setUpstreamSslConnection(info.downstreamSslConnection());

  if (parent_.downstream_end_stream_) {
    setupPerTryTimeout();
  } else {
    create_per_try_timeout_on_request_complete_ = true;
  }

  conn_pool_stream_handle_ = nullptr;
  setRequestEncoder(request_encoder);
  calling_encode_headers_ = true;
  if (parent_.route_entry_->autoHostRewrite() && !host->hostname().empty()) {
    parent_.downstream_headers_->Host()->value(host->hostname());
  }

  if (span_ != nullptr) {
    span_->injectContext(*parent_.downstream_headers_);
  }

  upstream_timing_.onFirstUpstreamTxByteSent(parent_.callbacks_->dispatcher().timeSource());

  const bool end_stream = !buffered_request_body_ && encode_complete_ && !encode_trailers_;
  // If end_stream is set in headers, and there are metadata to send, delays end_stream. The case
  // only happens when decoding headers filters return ContinueAndEndStream.
  const bool delay_headers_end_stream = end_stream && !downstream_metadata_map_vector_.empty();
  request_encoder.encodeHeaders(*parent_.downstream_headers_,
                                end_stream && !delay_headers_end_stream);
  calling_encode_headers_ = false;

  // It is possible to get reset in the middle of an encodeHeaders() call. This happens for example
  // in the HTTP/2 codec if the frame cannot be encoded for some reason. This should never happen
  // but it's unclear if we have covered all cases so protect against it and test for it. One
  // specific example of a case where this happens is if we try to encode a total header size that
  // is too big in HTTP/2 (64K currently).
  if (deferred_reset_reason_) {
    onResetStream(deferred_reset_reason_.value(), absl::string_view());
  } else {
    // Encode metadata after headers and before any other frame type.
    if (!downstream_metadata_map_vector_.empty()) {
      ENVOY_STREAM_LOG(debug, "Send metadata onPoolReady. {}", *parent_.callbacks_,
                       downstream_metadata_map_vector_);
      request_encoder.encodeMetadata(downstream_metadata_map_vector_);
      downstream_metadata_map_vector_.clear();
      if (delay_headers_end_stream) {
        Buffer::OwnedImpl empty_data("");
        request_encoder.encodeData(empty_data, true);
      }
    }

    if (buffered_request_body_) {
      stream_info_.addBytesSent(buffered_request_body_->length());
      request_encoder.encodeData(*buffered_request_body_, encode_complete_ && !encode_trailers_);
    }

    if (encode_trailers_) {
      request_encoder.encodeTrailers(*parent_.downstream_trailers_);
    }

    if (encode_complete_) {
      upstream_timing_.onLastUpstreamTxByteSent(parent_.callbacks_->dispatcher().timeSource());
    }
  }
}