// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "quiche/quic/tools/quic_simple_server_stream.h"

#include <list>
#include <memory>
#include <optional>
#include <utility>

#include "absl/base/macros.h"
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include "quiche/quic/core/crypto/null_encrypter.h"
#include "quiche/quic/core/http/http_encoder.h"
#include "quiche/quic/core/http/spdy_utils.h"
#include "quiche/quic/core/quic_alarm_factory.h"
#include "quiche/quic/core/quic_default_clock.h"
#include "quiche/quic/core/quic_error_codes.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/quic_utils.h"
#include "quiche/quic/platform/api/quic_expect_bug.h"
#include "quiche/quic/platform/api/quic_flags.h"
#include "quiche/quic/platform/api/quic_socket_address.h"
#include "quiche/quic/platform/api/quic_test.h"
#include "quiche/quic/test_tools/crypto_test_utils.h"
#include "quiche/quic/test_tools/quic_config_peer.h"
#include "quiche/quic/test_tools/quic_connection_peer.h"
#include "quiche/quic/test_tools/quic_session_peer.h"
#include "quiche/quic/test_tools/quic_spdy_session_peer.h"
#include "quiche/quic/test_tools/quic_stream_peer.h"
#include "quiche/quic/test_tools/quic_test_utils.h"
#include "quiche/quic/test_tools/simulator/simulator.h"
#include "quiche/quic/tools/quic_backend_response.h"
#include "quiche/quic/tools/quic_memory_cache_backend.h"
#include "quiche/quic/tools/quic_simple_server_backend.h"
#include "quiche/quic/tools/quic_simple_server_session.h"
#include "quiche/common/simple_buffer_allocator.h"

using testing::_;
using testing::AnyNumber;
using testing::InSequence;
using testing::Invoke;
using testing::StrictMock;

namespace quic {
namespace test {

const size_t kFakeFrameLen = 60;
const size_t kErrorLength = strlen(QuicSimpleServerStream::kErrorResponseBody);
const size_t kDataFrameHeaderLength = 2;

class TestStream : public QuicSimpleServerStream {
 public:
  TestStream(QuicStreamId stream_id, QuicSpdySession* session, StreamType type,
             QuicSimpleServerBackend* quic_simple_server_backend)
      : QuicSimpleServerStream(stream_id, session, type,
                               quic_simple_server_backend) {
    EXPECT_CALL(*this, WriteOrBufferBody(_, _))
        .Times(AnyNumber())
        .WillRepeatedly([this](absl::string_view data, bool fin) {
          this->QuicSimpleServerStream::WriteOrBufferBody(data, fin);
        });
  }

  ~TestStream() override = default;

  MOCK_METHOD(void, FireAlarmMock, (), ());
  MOCK_METHOD(void, WriteHeadersMock, (bool fin), ());
  MOCK_METHOD(void, WriteEarlyHintsHeadersMock, (bool fin), ());
  MOCK_METHOD(void, WriteOrBufferBody, (absl::string_view data, bool fin),
              (override));

  size_t WriteHeaders(
      spdy::Http2HeaderBlock header_block, bool fin,
      quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface>
      /*ack_listener*/) override {
    if (header_block[":status"] == "103") {
      WriteEarlyHintsHeadersMock(fin);
    } else {
      WriteHeadersMock(fin);
    }
    return 0;
  }

  // Expose protected QuicSimpleServerStream methods.
  void DoSendResponse() { SendResponse(); }
  void DoSendErrorResponse() { QuicSimpleServerStream::SendErrorResponse(); }

  spdy::Http2HeaderBlock* mutable_headers() { return &request_headers_; }
  void set_body(std::string body) { body_ = std::move(body); }
  const std::string& body() const { return body_; }
  int content_length() const { return content_length_; }
  bool send_response_was_called() const { return send_response_was_called_; }
  bool send_error_response_was_called() const {
    return send_error_response_was_called_;
  }

  absl::string_view GetHeader(absl::string_view key) const {
    auto it = request_headers_.find(key);
    QUICHE_DCHECK(it != request_headers_.end());
    return it->second;
  }

  void ReplaceBackend(QuicSimpleServerBackend* backend) {
    set_quic_simple_server_backend_for_test(backend);
  }

 protected:
  void SendResponse() override {
    send_response_was_called_ = true;
    QuicSimpleServerStream::SendResponse();
  }

  void SendErrorResponse(int resp_code) override {
    send_error_response_was_called_ = true;
    QuicSimpleServerStream::SendErrorResponse(resp_code);
  }

 private:
  bool send_response_was_called_ = false;
  bool send_error_response_was_called_ = false;
};

namespace {

class MockQuicSimpleServerSession : public QuicSimpleServerSession {
 public:
  const size_t kMaxStreamsForTest = 100;

  MockQuicSimpleServerSession(
      QuicConnection* connection, MockQuicSessionVisitor* owner,
      MockQuicCryptoServerStreamHelper* helper,
      QuicCryptoServerConfig* crypto_config,
      QuicCompressedCertsCache* compressed_certs_cache,
      QuicSimpleServerBackend* quic_simple_server_backend)
      : QuicSimpleServerSession(DefaultQuicConfig(), CurrentSupportedVersions(),
                                connection, owner, helper, crypto_config,
                                compressed_certs_cache,
                                quic_simple_server_backend) {
    if (VersionHasIetfQuicFrames(connection->transport_version())) {
      QuicSessionPeer::SetMaxOpenIncomingUnidirectionalStreams(
          this, kMaxStreamsForTest);
      QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(
          this, kMaxStreamsForTest);
    } else {
      QuicSessionPeer::SetMaxOpenIncomingStreams(this, kMaxStreamsForTest);
      QuicSessionPeer::SetMaxOpenOutgoingStreams(this, kMaxStreamsForTest);
    }
    ON_CALL(*this, WritevData(_, _, _, _, _, _))
        .WillByDefault(Invoke(this, &MockQuicSimpleServerSession::ConsumeData));
  }

  MockQuicSimpleServerSession(const MockQuicSimpleServerSession&) = delete;
  MockQuicSimpleServerSession& operator=(const MockQuicSimpleServerSession&) =
      delete;
  ~MockQuicSimpleServerSession() override = default;

  MOCK_METHOD(void, OnConnectionClosed,
              (const QuicConnectionCloseFrame& frame,
               ConnectionCloseSource source),
              (override));
  MOCK_METHOD(QuicSpdyStream*, CreateIncomingStream, (QuicStreamId id),
              (override));
  MOCK_METHOD(QuicConsumedData, WritevData,
              (QuicStreamId id, size_t write_length, QuicStreamOffset offset,
               StreamSendingState state, TransmissionType type,
               EncryptionLevel level),
              (override));
  MOCK_METHOD(void, OnStreamHeaderList,
              (QuicStreamId stream_id, bool fin, size_t frame_len,
               const QuicHeaderList& header_list),
              (override));
  MOCK_METHOD(void, OnStreamHeadersPriority,
              (QuicStreamId stream_id,
               const spdy::SpdyStreamPrecedence& precedence),
              (override));
  MOCK_METHOD(void, MaybeSendRstStreamFrame,
              (QuicStreamId stream_id, QuicResetStreamError error,
               QuicStreamOffset bytes_written),
              (override));
  MOCK_METHOD(void, MaybeSendStopSendingFrame,
              (QuicStreamId stream_id, QuicResetStreamError error), (override));

  using QuicSession::ActivateStream;

  QuicConsumedData ConsumeData(QuicStreamId id, size_t write_length,
                               QuicStreamOffset offset,
                               StreamSendingState state,
                               TransmissionType /*type*/,
                               std::optional<EncryptionLevel> /*level*/) {
    if (write_length > 0) {
      auto buf = std::make_unique<char[]>(write_length);
      QuicStream* stream = GetOrCreateStream(id);
      QUICHE_DCHECK(stream);
      QuicDataWriter writer(write_length, buf.get(), quiche::HOST_BYTE_ORDER);
      stream->WriteStreamData(offset, write_length, &writer);
    } else {
      QUICHE_DCHECK(state != NO_FIN);
    }
    return QuicConsumedData(write_length, state != NO_FIN);
  }

  spdy::Http2HeaderBlock original_request_headers_;
};

class QuicSimpleServerStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
 public:
  QuicSimpleServerStreamTest()
      : connection_(new StrictMock<MockQuicConnection>(
            &simulator_, simulator_.GetAlarmFactory(), Perspective::IS_SERVER,
            SupportedVersions(GetParam()))),
        crypto_config_(new QuicCryptoServerConfig(
            QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
            crypto_test_utils::ProofSourceForTesting(),
            KeyExchangeSource::Default())),
        compressed_certs_cache_(
            QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
        session_(connection_, &session_owner_, &session_helper_,
                 crypto_config_.get(), &compressed_certs_cache_,
                 &memory_cache_backend_),
        quic_response_(new QuicBackendResponse),
        body_("hello world") {
    connection_->set_visitor(&session_);
    header_list_.OnHeaderBlockStart();
    header_list_.OnHeader(":authority", "www.google.com");
    header_list_.OnHeader(":path", "/");
    header_list_.OnHeader(":method", "POST");
    header_list_.OnHeader(":scheme", "https");
    header_list_.OnHeader("content-length", "11");

    header_list_.OnHeaderBlockEnd(128, 128);

    // New streams rely on having the peer's flow control receive window
    // negotiated in the config.
    session_.config()->SetInitialStreamFlowControlWindowToSend(
        kInitialStreamFlowControlWindowForTest);
    session_.config()->SetInitialSessionFlowControlWindowToSend(
        kInitialSessionFlowControlWindowForTest);
    session_.Initialize();
    connection_->SetEncrypter(
        quic::ENCRYPTION_FORWARD_SECURE,
        std::make_unique<quic::NullEncrypter>(connection_->perspective()));
    if (connection_->version().SupportsAntiAmplificationLimit()) {
      QuicConnectionPeer::SetAddressValidated(connection_);
    }
    stream_ = new StrictMock<TestStream>(
        GetNthClientInitiatedBidirectionalStreamId(
            connection_->transport_version(), 0),
        &session_, BIDIRECTIONAL, &memory_cache_backend_);
    // Register stream_ in dynamic_stream_map_ and pass ownership to session_.
    session_.ActivateStream(absl::WrapUnique(stream_));
    QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
        session_.config(), kMinimumFlowControlSendWindow);
    QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesUnidirectional(
        session_.config(), kMinimumFlowControlSendWindow);
    QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesIncomingBidirectional(
        session_.config(), kMinimumFlowControlSendWindow);
    QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesOutgoingBidirectional(
        session_.config(), kMinimumFlowControlSendWindow);
    QuicConfigPeer::SetReceivedMaxUnidirectionalStreams(session_.config(), 10);
    session_.OnConfigNegotiated();
    simulator_.RunFor(QuicTime::Delta::FromSeconds(1));
  }

  const std::string& StreamBody() { return stream_->body(); }

  std::string StreamHeadersValue(const std::string& key) {
    return (*stream_->mutable_headers())[key].as_string();
  }

  bool UsesHttp3() const {
    return VersionUsesHttp3(connection_->transport_version());
  }

  void ReplaceBackend(std::unique_ptr<QuicSimpleServerBackend> backend) {
    replacement_backend_ = std::move(backend);
    stream_->ReplaceBackend(replacement_backend_.get());
  }

  quic::simulator::Simulator simulator_;
  spdy::Http2HeaderBlock response_headers_;
  MockQuicConnectionHelper helper_;
  StrictMock<MockQuicConnection>* connection_;
  StrictMock<MockQuicSessionVisitor> session_owner_;
  StrictMock<MockQuicCryptoServerStreamHelper> session_helper_;
  std::unique_ptr<QuicCryptoServerConfig> crypto_config_;
  QuicCompressedCertsCache compressed_certs_cache_;
  QuicMemoryCacheBackend memory_cache_backend_;
  std::unique_ptr<QuicSimpleServerBackend> replacement_backend_;
  StrictMock<MockQuicSimpleServerSession> session_;
  StrictMock<TestStream>* stream_;  // Owned by session_.
  std::unique_ptr<QuicBackendResponse> quic_response_;
  std::string body_;
  QuicHeaderList header_list_;
};

INSTANTIATE_TEST_SUITE_P(Tests, QuicSimpleServerStreamTest,
                         ::testing::ValuesIn(AllSupportedVersions()),
                         ::testing::PrintToStringParamName());

TEST_P(QuicSimpleServerStreamTest, TestFraming) {
  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
      .WillRepeatedly(
          Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));
  stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
  quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
      body_.length(), quiche::SimpleBufferAllocator::Get());
  std::string data =
      UsesHttp3() ? absl::StrCat(header.AsStringView(), body_) : body_;
  stream_->OnStreamFrame(
      QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
  EXPECT_EQ("11", StreamHeadersValue("content-length"));
  EXPECT_EQ("/", StreamHeadersValue(":path"));
  EXPECT_EQ("POST", StreamHeadersValue(":method"));
  EXPECT_EQ(body_, StreamBody());
}

TEST_P(QuicSimpleServerStreamTest, TestFramingOnePacket) {
  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
      .WillRepeatedly(
          Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));

  stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
  quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
      body_.length(), quiche::SimpleBufferAllocator::Get());
  std::string data =
      UsesHttp3() ? absl::StrCat(header.AsStringView(), body_) : body_;
  stream_->OnStreamFrame(
      QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
  EXPECT_EQ("11", StreamHeadersValue("content-length"));
  EXPECT_EQ("/", StreamHeadersValue(":path"));
  EXPECT_EQ("POST", StreamHeadersValue(":method"));
  EXPECT_EQ(body_, StreamBody());
}

TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading) {
  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
      .WillRepeatedly(
          Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));

  EXPECT_FALSE(stream_->fin_received());
  EXPECT_FALSE(stream_->rst_received());

  QuicStreamPeer::SetFinSent(stream_);
  stream_->CloseWriteSide();

  if (session_.version().UsesHttp3()) {
    EXPECT_CALL(session_,
                MaybeSendStopSendingFrame(_, QuicResetStreamError::FromInternal(
                                                 QUIC_STREAM_NO_ERROR)))
        .Times(1);
  } else {
    EXPECT_CALL(
        session_,
        MaybeSendRstStreamFrame(
            _, QuicResetStreamError::FromInternal(QUIC_STREAM_NO_ERROR), _))
        .Times(1);
  }
  stream_->StopReading();
}

TEST_P(QuicSimpleServerStreamTest, TestFramingExtraData) {
  InSequence seq;
  std::string large_body = "hello world!!!!!!";

  // We'll automatically write out an error (headers + body)
  EXPECT_CALL(*stream_, WriteHeadersMock(false));
  if (UsesHttp3()) {
    EXPECT_CALL(session_,
                WritevData(_, kDataFrameHeaderLength, _, NO_FIN, _, _));
  }
  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _, _));

  stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
  quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
      body_.length(), quiche::SimpleBufferAllocator::Get());
  std::string data =
      UsesHttp3() ? absl::StrCat(header.AsStringView(), body_) : body_;

  stream_->OnStreamFrame(
      QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
  // Content length is still 11.  This will register as an error and we won't
  // accept the bytes.
  header = HttpEncoder::SerializeDataFrameHeader(
      large_body.length(), quiche::SimpleBufferAllocator::Get());
  std::string data2 = UsesHttp3()
                          ? absl::StrCat(header.AsStringView(), large_body)
                          : large_body;
  stream_->OnStreamFrame(
      QuicStreamFrame(stream_->id(), /*fin=*/true, data.size(), data2));
  EXPECT_EQ("11", StreamHeadersValue("content-length"));
  EXPECT_EQ("/", StreamHeadersValue(":path"));
  EXPECT_EQ("POST", StreamHeadersValue(":method"));
}

TEST_P(QuicSimpleServerStreamTest, SendResponseWithIllegalResponseStatus) {
  // Send an illegal response with response status not supported by HTTP/2.
  spdy::Http2HeaderBlock* request_headers = stream_->mutable_headers();
  (*request_headers)[":path"] = "/bar";
  (*request_headers)[":authority"] = "www.google.com";
  (*request_headers)[":method"] = "GET";

  // HTTP/2 only supports integer responsecode, so "200 OK" is illegal.
  response_headers_[":status"] = "200 OK";
  response_headers_["content-length"] = "5";
  std::string body = "Yummm";
  quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
      body.length(), quiche::SimpleBufferAllocator::Get());

  memory_cache_backend_.AddResponse("www.google.com", "/bar",
                                    std::move(response_headers_), body);

  QuicStreamPeer::SetFinReceived(stream_);

  InSequence s;
  EXPECT_CALL(*stream_, WriteHeadersMock(false));
  if (UsesHttp3()) {
    EXPECT_CALL(session_, WritevData(_, header.size(), _, NO_FIN, _, _));
  }
  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _, _));

  stream_->DoSendResponse();
  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
  EXPECT_TRUE(stream_->write_side_closed());
}

TEST_P(QuicSimpleServerStreamTest, SendResponseWithIllegalResponseStatus2) {
  // Send an illegal response with response status not supported by HTTP/2.
  spdy::Http2HeaderBlock* request_headers = stream_->mutable_headers();
  (*request_headers)[":path"] = "/bar";
  (*request_headers)[":authority"] = "www.google.com";
  (*request_headers)[":method"] = "GET";

  // HTTP/2 only supports 3-digit-integer, so "+200" is illegal.
  response_headers_[":status"] = "+200";
  response_headers_["content-length"] = "5";
  std::string body = "Yummm";

  quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
      body.length(), quiche::SimpleBufferAllocator::Get());

  memory_cache_backend_.AddResponse("www.google.com", "/bar",
                                    std::move(response_headers_), body);

  QuicStreamPeer::SetFinReceived(stream_);

  InSequence s;
  EXPECT_CALL(*stream_, WriteHeadersMock(false));
  if (UsesHttp3()) {
    EXPECT_CALL(session_, WritevData(_, header.size(), _, NO_FIN, _, _));
  }
  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _, _));

  stream_->DoSendResponse();
  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
  EXPECT_TRUE(stream_->write_side_closed());
}

TEST_P(QuicSimpleServerStreamTest, SendResponseWithValidHeaders) {
  // Add a request and response with valid headers.
  spdy::Http2HeaderBlock* request_headers = stream_->mutable_headers();
  (*request_headers)[":path"] = "/bar";
  (*request_headers)[":authority"] = "www.google.com";
  (*request_headers)[":method"] = "GET";

  response_headers_[":status"] = "200";
  response_headers_["content-length"] = "5";
  std::string body = "Yummm";

  quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
      body.length(), quiche::SimpleBufferAllocator::Get());

  memory_cache_backend_.AddResponse("www.google.com", "/bar",
                                    std::move(response_headers_), body);
  QuicStreamPeer::SetFinReceived(stream_);

  InSequence s;
  EXPECT_CALL(*stream_, WriteHeadersMock(false));
  if (UsesHttp3()) {
    EXPECT_CALL(session_, WritevData(_, header.size(), _, NO_FIN, _, _));
  }
  EXPECT_CALL(session_, WritevData(_, body.length(), _, FIN, _, _));

  stream_->DoSendResponse();
  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
  EXPECT_TRUE(stream_->write_side_closed());
}

TEST_P(QuicSimpleServerStreamTest, SendResponseWithEarlyHints) {
  std::string host = "www.google.com";
  std::string request_path = "/foo";
  std::string body = "Yummm";

  // Add a request and response with early hints.
  spdy::Http2HeaderBlock* request_headers = stream_->mutable_headers();
  (*request_headers)[":path"] = request_path;
  (*request_headers)[":authority"] = host;
  (*request_headers)[":method"] = "GET";

  quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
      body.length(), quiche::SimpleBufferAllocator::Get());
  std::vector<spdy::Http2HeaderBlock> early_hints;
  // Add two Early Hints.
  const size_t kNumEarlyHintsResponses = 2;
  for (size_t i = 0; i < kNumEarlyHintsResponses; ++i) {
    spdy::Http2HeaderBlock hints;
    hints["link"] = "</image.png>; rel=preload; as=image";
    early_hints.push_back(std::move(hints));
  }

  response_headers_[":status"] = "200";
  response_headers_["content-length"] = "5";
  memory_cache_backend_.AddResponseWithEarlyHints(
      host, request_path, std::move(response_headers_), body, early_hints);
  QuicStreamPeer::SetFinReceived(stream_);

  InSequence s;
  for (size_t i = 0; i < kNumEarlyHintsResponses; ++i) {
    EXPECT_CALL(*stream_, WriteEarlyHintsHeadersMock(false));
  }
  EXPECT_CALL(*stream_, WriteHeadersMock(false));
  if (UsesHttp3()) {
    EXPECT_CALL(session_, WritevData(_, header.size(), _, NO_FIN, _, _));
  }
  EXPECT_CALL(session_, WritevData(_, body.length(), _, FIN, _, _));

  stream_->DoSendResponse();
  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
  EXPECT_TRUE(stream_->write_side_closed());
}

class AlarmTestDelegate : public QuicAlarm::DelegateWithoutContext {
 public:
  AlarmTestDelegate(TestStream* stream) : stream_(stream) {}

  void OnAlarm() override { stream_->FireAlarmMock(); }

 private:
  TestStream* stream_;
};

TEST_P(QuicSimpleServerStreamTest, SendResponseWithDelay) {
  // Add a request and response with valid headers.
  spdy::Http2HeaderBlock* request_headers = stream_->mutable_headers();
  std::string host = "www.google.com";
  std::string path = "/bar";
  (*request_headers)[":path"] = path;
  (*request_headers)[":authority"] = host;
  (*request_headers)[":method"] = "GET";

  response_headers_[":status"] = "200";
  response_headers_["content-length"] = "5";
  std::string body = "Yummm";
  QuicTime::Delta delay = QuicTime::Delta::FromMilliseconds(3000);

  quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
      body.length(), quiche::SimpleBufferAllocator::Get());

  memory_cache_backend_.AddResponse(host, path, std::move(response_headers_),
                                    body);
  auto did_delay_succeed =
      memory_cache_backend_.SetResponseDelay(host, path, delay);
  EXPECT_TRUE(did_delay_succeed);
  auto did_invalid_delay_succeed =
      memory_cache_backend_.SetResponseDelay(host, "nonsense", delay);
  EXPECT_FALSE(did_invalid_delay_succeed);
  std::unique_ptr<QuicAlarm> alarm(connection_->alarm_factory()->CreateAlarm(
      new AlarmTestDelegate(stream_)));
  alarm->Set(connection_->clock()->Now() + delay);
  QuicStreamPeer::SetFinReceived(stream_);
  InSequence s;
  EXPECT_CALL(*stream_, FireAlarmMock());
  EXPECT_CALL(*stream_, WriteHeadersMock(false));

  if (UsesHttp3()) {
    EXPECT_CALL(session_, WritevData(_, header.size(), _, NO_FIN, _, _));
  }
  EXPECT_CALL(session_, WritevData(_, body.length(), _, FIN, _, _));

  stream_->DoSendResponse();
  simulator_.RunFor(delay);

  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
  EXPECT_TRUE(stream_->write_side_closed());
}

TEST_P(QuicSimpleServerStreamTest, TestSendErrorResponse) {
  QuicStreamPeer::SetFinReceived(stream_);

  InSequence s;
  EXPECT_CALL(*stream_, WriteHeadersMock(false));
  if (UsesHttp3()) {
    EXPECT_CALL(session_,
                WritevData(_, kDataFrameHeaderLength, _, NO_FIN, _, _));
  }
  EXPECT_CALL(session_, WritevData(_, kErrorLength, _, FIN, _, _));

  stream_->DoSendErrorResponse();
  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
  EXPECT_TRUE(stream_->write_side_closed());
}

TEST_P(QuicSimpleServerStreamTest, InvalidMultipleContentLength) {
  spdy::Http2HeaderBlock request_headers;
  // \000 is a way to write the null byte when followed by a literal digit.
  header_list_.OnHeader("content-length", absl::string_view("11\00012", 5));

  if (session_.version().UsesHttp3()) {
    EXPECT_CALL(session_,
                MaybeSendStopSendingFrame(_, QuicResetStreamError::FromInternal(
                                                 QUIC_STREAM_NO_ERROR)));
  }
  EXPECT_CALL(*stream_, WriteHeadersMock(false));
  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
      .WillRepeatedly(
          Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));
  stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_);

  EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_));
  EXPECT_TRUE(stream_->reading_stopped());
  EXPECT_TRUE(stream_->write_side_closed());
}

TEST_P(QuicSimpleServerStreamTest, InvalidLeadingNullContentLength) {
  spdy::Http2HeaderBlock request_headers;
  // \000 is a way to write the null byte when followed by a literal digit.
  header_list_.OnHeader("content-length", absl::string_view("\00012", 3));

  if (session_.version().UsesHttp3()) {
    EXPECT_CALL(session_,
                MaybeSendStopSendingFrame(_, QuicResetStreamError::FromInternal(
                                                 QUIC_STREAM_NO_ERROR)));
  }
  EXPECT_CALL(*stream_, WriteHeadersMock(false));
  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
      .WillRepeatedly(
          Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));
  stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_);

  EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_));
  EXPECT_TRUE(stream_->reading_stopped());
  EXPECT_TRUE(stream_->write_side_closed());
}

TEST_P(QuicSimpleServerStreamTest, InvalidMultipleContentLengthII) {
  spdy::Http2HeaderBlock request_headers;
  // \000 is a way to write the null byte when followed by a literal digit.
  header_list_.OnHeader("content-length", absl::string_view("11\00011", 5));

  if (session_.version().UsesHttp3()) {
    EXPECT_CALL(session_,
                MaybeSendStopSendingFrame(_, QuicResetStreamError::FromInternal(
                                                 QUIC_STREAM_NO_ERROR)));
    EXPECT_CALL(*stream_, WriteHeadersMock(false));
    EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
        .WillRepeatedly(
            Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));
  }

  stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);

  if (session_.version().UsesHttp3()) {
    EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_));
    EXPECT_TRUE(stream_->reading_stopped());
    EXPECT_TRUE(stream_->write_side_closed());
  } else {
    EXPECT_EQ(11, stream_->content_length());
    EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
    EXPECT_FALSE(stream_->reading_stopped());
    EXPECT_FALSE(stream_->write_side_closed());
  }
}

TEST_P(QuicSimpleServerStreamTest,
       DoNotSendQuicRstStreamNoErrorWithRstReceived) {
  EXPECT_FALSE(stream_->reading_stopped());

  if (VersionUsesHttp3(connection_->transport_version())) {
    // Unidirectional stream type and then a Stream Cancellation instruction is
    // sent on the QPACK decoder stream.  Ignore these writes without any
    // assumption on their number or size.
    auto* qpack_decoder_stream =
        QuicSpdySessionPeer::GetQpackDecoderSendStream(&session_);
    EXPECT_CALL(session_, WritevData(qpack_decoder_stream->id(), _, _, _, _, _))
        .Times(AnyNumber());
  }

  EXPECT_CALL(
      session_,
      MaybeSendRstStreamFrame(
          _,
          session_.version().UsesHttp3()
              ? QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED)
              : QuicResetStreamError::FromInternal(QUIC_RST_ACKNOWLEDGEMENT),
          _))
      .Times(1);
  QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
                               QUIC_STREAM_CANCELLED, 1234);
  stream_->OnStreamReset(rst_frame);
  if (VersionHasIetfQuicFrames(connection_->transport_version())) {
    EXPECT_CALL(session_owner_, OnStopSendingReceived(_));
    // Create and inject a STOP SENDING frame to complete the close
    // of the stream. This is only needed for version 99/IETF QUIC.
    QuicStopSendingFrame stop_sending(kInvalidControlFrameId, stream_->id(),
                                      QUIC_STREAM_CANCELLED);
    session_.OnStopSendingFrame(stop_sending);
  }
  EXPECT_TRUE(stream_->reading_stopped());
  EXPECT_TRUE(stream_->write_side_closed());
}

TEST_P(QuicSimpleServerStreamTest, InvalidHeadersWithFin) {
  char arr[] = {
      0x3a,   0x68, 0x6f, 0x73,  // :hos
      0x74,   0x00, 0x00, 0x00,  // t...
      0x00,   0x00, 0x00, 0x00,  // ....
      0x07,   0x3a, 0x6d, 0x65,  // .:me
      0x74,   0x68, 0x6f, 0x64,  // thod
      0x00,   0x00, 0x00, 0x03,  // ....
      0x47,   0x45, 0x54, 0x00,  // GET.
      0x00,   0x00, 0x05, 0x3a,  // ...:
      0x70,   0x61, 0x74, 0x68,  // path
      0x00,   0x00, 0x00, 0x04,  // ....
      0x2f,   0x66, 0x6f, 0x6f,  // /foo
      0x00,   0x00, 0x00, 0x07,  // ....
      0x3a,   0x73, 0x63, 0x68,  // :sch
      0x65,   0x6d, 0x65, 0x00,  // eme.
      0x00,   0x00, 0x00, 0x00,  // ....
      0x00,   0x00, 0x08, 0x3a,  // ...:
      0x76,   0x65, 0x72, 0x73,  // vers
      '\x96', 0x6f, 0x6e, 0x00,  // <i(69)>on.
      0x00,   0x00, 0x08, 0x48,  // ...H
      0x54,   0x54, 0x50, 0x2f,  // TTP/
      0x31,   0x2e, 0x31,        // 1.1
  };
  absl::string_view data(arr, ABSL_ARRAYSIZE(arr));
  QuicStreamFrame frame(stream_->id(), true, 0, data);
  // Verify that we don't crash when we get a invalid headers in stream frame.
  stream_->OnStreamFrame(frame);
}

// Basic QuicSimpleServerBackend that implements its behavior through mocking.
class TestQuicSimpleServerBackend : public QuicSimpleServerBackend {
 public:
  TestQuicSimpleServerBackend() = default;
  ~TestQuicSimpleServerBackend() override = default;

  // QuicSimpleServerBackend:
  bool InitializeBackend(const std::string& /*backend_url*/) override {
    return true;
  }
  bool IsBackendInitialized() const override { return true; }
  MOCK_METHOD(void, FetchResponseFromBackend,
              (const spdy::Http2HeaderBlock&, const std::string&,
               RequestHandler*),
              (override));
  MOCK_METHOD(void, HandleConnectHeaders,
              (const spdy::Http2HeaderBlock&, RequestHandler*), (override));
  MOCK_METHOD(void, HandleConnectData,
              (absl::string_view, bool, RequestHandler*), (override));
  void CloseBackendResponseStream(
      RequestHandler* /*request_handler*/) override {}
};

ACTION_P(SendHeadersResponse, response_ptr) {
  arg1->OnResponseBackendComplete(response_ptr);
}

ACTION_P(SendStreamData, data, close_stream) {
  arg2->SendStreamData(data, close_stream);
}

ACTION_P(TerminateStream, error) { arg1->TerminateStreamWithError(error); }

TEST_P(QuicSimpleServerStreamTest, ConnectSendsIntermediateResponses) {
  auto test_backend = std::make_unique<TestQuicSimpleServerBackend>();
  TestQuicSimpleServerBackend* test_backend_ptr = test_backend.get();
  ReplaceBackend(std::move(test_backend));

  constexpr absl::string_view kRequestBody = "\x11\x11";
  spdy::Http2HeaderBlock response_headers;
  response_headers[":status"] = "200";
  QuicBackendResponse headers_response;
  headers_response.set_headers(response_headers.Clone());
  headers_response.set_response_type(QuicBackendResponse::INCOMPLETE_RESPONSE);
  constexpr absl::string_view kBody1 = "\x22\x22";
  constexpr absl::string_view kBody2 = "\x33\x33";

  // Expect an initial headers-only request to result in a headers-only
  // incomplete response. Then a data frame without fin, resulting in stream
  // data. Then a data frame with fin, resulting in stream data with fin.
  InSequence s;
  EXPECT_CALL(*test_backend_ptr, HandleConnectHeaders(_, _))
      .WillOnce(SendHeadersResponse(&headers_response));
  EXPECT_CALL(*stream_, WriteHeadersMock(false));
  EXPECT_CALL(*test_backend_ptr, HandleConnectData(kRequestBody, false, _))
      .WillOnce(SendStreamData(kBody1,
                               /*close_stream=*/false));
  EXPECT_CALL(*stream_, WriteOrBufferBody(kBody1, false));
  EXPECT_CALL(*test_backend_ptr, HandleConnectData(kRequestBody, true, _))
      .WillOnce(SendStreamData(kBody2,
                               /*close_stream=*/true));
  EXPECT_CALL(*stream_, WriteOrBufferBody(kBody2, true));

  QuicHeaderList header_list;
  header_list.OnHeaderBlockStart();
  header_list.OnHeader(":authority", "www.google.com:4433");
  header_list.OnHeader(":method", "CONNECT");
  header_list.OnHeaderBlockEnd(128, 128);

  stream_->OnStreamHeaderList(/*fin=*/false, kFakeFrameLen, header_list);
  quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
      kRequestBody.length(), quiche::SimpleBufferAllocator::Get());
  std::string data = UsesHttp3()
                         ? absl::StrCat(header.AsStringView(), kRequestBody)
                         : std::string(kRequestBody);
  stream_->OnStreamFrame(
      QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
  stream_->OnStreamFrame(
      QuicStreamFrame(stream_->id(), /*fin=*/true, data.length(), data));

  // Expect to not go through SendResponse().
  EXPECT_FALSE(stream_->send_response_was_called());
  EXPECT_FALSE(stream_->send_error_response_was_called());
}

TEST_P(QuicSimpleServerStreamTest, ErrorOnUnhandledConnect) {
  // Expect single set of failure response headers with FIN in response to the
  // headers. Then, expect abrupt stream termination in response to the body.
  EXPECT_CALL(*stream_, WriteHeadersMock(true));
  EXPECT_CALL(session_, MaybeSendRstStreamFrame(stream_->id(), _, _));

  QuicHeaderList header_list;
  header_list.OnHeaderBlockStart();
  header_list.OnHeader(":authority", "www.google.com:4433");
  header_list.OnHeader(":method", "CONNECT");
  header_list.OnHeaderBlockEnd(128, 128);
  constexpr absl::string_view kRequestBody = "\x11\x11";

  stream_->OnStreamHeaderList(/*fin=*/false, kFakeFrameLen, header_list);
  quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
      kRequestBody.length(), quiche::SimpleBufferAllocator::Get());
  std::string data = UsesHttp3()
                         ? absl::StrCat(header.AsStringView(), kRequestBody)
                         : std::string(kRequestBody);
  stream_->OnStreamFrame(
      QuicStreamFrame(stream_->id(), /*fin=*/true, /*offset=*/0, data));

  // Expect failure to not go through SendResponse().
  EXPECT_FALSE(stream_->send_response_was_called());
  EXPECT_FALSE(stream_->send_error_response_was_called());
}

TEST_P(QuicSimpleServerStreamTest, ConnectWithInvalidHeader) {
  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
      .WillRepeatedly(
          Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));
  QuicHeaderList header_list;
  header_list.OnHeaderBlockStart();
  header_list.OnHeader(":authority", "www.google.com:4433");
  header_list.OnHeader(":method", "CONNECT");
  // QUIC requires lower-case header names.
  header_list.OnHeader("InVaLiD-HeAdEr", "Well that's just wrong!");
  header_list.OnHeaderBlockEnd(128, 128);

  if (UsesHttp3()) {
    EXPECT_CALL(session_,
                MaybeSendStopSendingFrame(_, QuicResetStreamError::FromInternal(
                                                 QUIC_STREAM_NO_ERROR)))
        .Times(1);
  } else {
    EXPECT_CALL(
        session_,
        MaybeSendRstStreamFrame(
            _, QuicResetStreamError::FromInternal(QUIC_STREAM_NO_ERROR), _))
        .Times(1);
  }
  EXPECT_CALL(*stream_, WriteHeadersMock(/*fin=*/false));
  stream_->OnStreamHeaderList(/*fin=*/false, kFakeFrameLen, header_list);
  EXPECT_FALSE(stream_->send_response_was_called());
  EXPECT_TRUE(stream_->send_error_response_was_called());
}

TEST_P(QuicSimpleServerStreamTest, BackendCanTerminateStream) {
  auto test_backend = std::make_unique<TestQuicSimpleServerBackend>();
  TestQuicSimpleServerBackend* test_backend_ptr = test_backend.get();
  ReplaceBackend(std::move(test_backend));

  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
      .WillRepeatedly(
          Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));

  QuicResetStreamError expected_error =
      QuicResetStreamError::FromInternal(QUIC_STREAM_CONNECT_ERROR);
  EXPECT_CALL(*test_backend_ptr, HandleConnectHeaders(_, _))
      .WillOnce(TerminateStream(expected_error));
  EXPECT_CALL(session_,
              MaybeSendRstStreamFrame(stream_->id(), expected_error, _));

  QuicHeaderList header_list;
  header_list.OnHeaderBlockStart();
  header_list.OnHeader(":authority", "www.google.com:4433");
  header_list.OnHeader(":method", "CONNECT");
  header_list.OnHeaderBlockEnd(128, 128);
  stream_->OnStreamHeaderList(/*fin=*/false, kFakeFrameLen, header_list);
}

}  // namespace
}  // namespace test
}  // namespace quic
