text: // Copyright 2016 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 "net/quic/bidirectional_stream_quic_impl.h"
  
  #include <memory>
  #include <utility>
  
  #include "base/memory/ptr_util.h"
  #include "base/run_loop.h"
  #include "base/strings/strcat.h"
  #include "base/strings/string_number_conversions.h"
  #include "base/threading/thread_task_runner_handle.h"
  #include "base/time/default_tick_clock.h"
  #include "base/time/time.h"
  #include "base/timer/timer.h"
  #include "net/base/completion_once_callback.h"
  #include "net/base/ip_address.h"
  #include "net/base/load_timing_info.h"
  #include "net/base/load_timing_info_test_util.h"
  #include "net/base/net_errors.h"
  #include "net/dns/public/secure_dns_policy.h"
  #include "net/http/bidirectional_stream_request_info.h"
  #include "net/http/transport_security_state.h"
  #include "net/log/net_log_event_type.h"
  #include "net/log/test_net_log.h"
  #include "net/log/test_net_log_util.h"
  #include "net/quic/address_utils.h"
  #include "net/quic/mock_crypto_client_stream_factory.h"
  #include "net/quic/platform/impl/quic_test_impl.h"
  #include "net/quic/quic_chromium_alarm_factory.h"
  #include "net/quic/quic_chromium_connection_helper.h"
  #include "net/quic/quic_chromium_packet_reader.h"
  #include "net/quic/quic_chromium_packet_writer.h"
  #include "net/quic/quic_crypto_client_config_handle.h"
  #include "net/quic/quic_http_utils.h"
  #include "net/quic/quic_server_info.h"
  #include "net/quic/quic_stream_factory.h"
  #include "net/quic/quic_test_packet_maker.h"
  #include "net/quic/quic_test_packet_printer.h"
  #include "net/quic/test_quic_crypto_client_config_handle.h"
  #include "net/quic/test_task_runner.h"
  #include "net/socket/socket_test_util.h"
  #include "net/test/gtest_util.h"
  #include "net/test/test_with_task_environment.h"
  #include "net/third_party/quiche/src/common/quiche_text_utils.h"
  #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
  #include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h"
  #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
  #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
  #include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
  #include "net/third_party/quiche/src/quic/core/quic_connection.h"
  #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
  #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
  #include "net/third_party/quiche/src/quic/test_tools/mock_random.h"
  #include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h"
  #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
  #include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
  #include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
  #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
  #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
  #include "testing/gmock/include/gmock/gmock.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  namespace net {
  
  namespace test {
  
  namespace {
  
  const char kUploadData[] = "Really nifty data!";
  const char kDefaultServerHostName[] = "www.google.com";
  const uint16_t kDefaultServerPort = 80;
  // Size of the buffer to be allocated for each read.
  const size_t kReadBufferSize = 4096;
  
  enum DelegateMethod {
    kOnStreamReady,
    kOnHeadersReceived,
    kOnTrailersReceived,
    kOnDataRead,
    kOnDataSent,
    kOnFailed
  };
  
  struct TestParams {
    quic::ParsedQuicVersion version;
    bool client_headers_include_h2_stream_dependency;
  };
  
  // Used by ::testing::PrintToStringParamName().
  std::string PrintToString(const TestParams& p) {
    return base::StrCat(
        {ParsedQuicVersionToString(p.version), "_",
         (p.client_headers_include_h2_stream_dependency ? "" : "No"),
         "Dependency"});
  }
  
  std::vector<TestParams> GetTestParams() {
    std::vector<TestParams> params;
    quic::ParsedQuicVersionVector all_supported_versions =
        quic::AllSupportedVersions();
    for (const auto& version : all_supported_versions) {
      params.push_back(TestParams{version, false});
      params.push_back(TestParams{version, true});
    }
    return params;
  }
  
  class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
   public:
    TestDelegateBase(IOBuffer* read_buf, int read_buf_len)
        : TestDelegateBase(read_buf,
                           read_buf_len,
                           std::make_unique<base::OneShotTimer>()) {}
  
    TestDelegateBase(IOBuffer* read_buf,
                     int read_buf_len,
                     std::unique_ptr<base::OneShotTimer> timer)
        : read_buf_(read_buf),
          read_buf_len_(read_buf_len),
          timer_(std::move(timer)),
          loop_(nullptr),
          next_proto_(kProtoUnknown),
          received_bytes_(0),
          sent_bytes_(0),
          has_load_timing_info_(false),
          error_(OK),
          on_data_read_count_(0),
          on_data_sent_count_(0),
          not_expect_callback_(false),
          on_failed_called_(false),
          send_request_headers_automatically_(true),
          is_ready_(false),
          trailers_expected_(false),
          trailers_received_(false) {
      loop_ = std::make_unique<base::RunLoop>();
    }
  
    ~TestDelegateBase() override {}
  
    void OnStreamReady(bool request_headers_sent) override {
      CHECK(!is_ready_);
      CHECK(!on_failed_called_);
      EXPECT_EQ(send_request_headers_automatically_, request_headers_sent);
      CHECK(!not_expect_callback_);
      is_ready_ = true;
      loop_->Quit();
    }
  
    void OnHeadersReceived(
        const spdy::Http2HeaderBlock& response_headers) override {
      CHECK(!on_failed_called_);
      CHECK(!not_expect_callback_);
  
      response_headers_ = response_headers.Clone();
      loop_->Quit();
    }
  
    void OnDataRead(int bytes_read) override {
      CHECK(!on_failed_called_);
      CHECK(!not_expect_callback_);
      CHECK(!callback_.is_null());
  
      // If read EOF, make sure this callback is after trailers callback.
      if (bytes_read == 0)
        EXPECT_TRUE(!trailers_expected_ || trailers_received_);
      ++on_data_read_count_;
      CHECK_GE(bytes_read, OK);
      data_received_.append(read_buf_->data(), bytes_read);
      std::move(callback_).Run(bytes_read);
    }
  
    void OnDataSent() override {
      CHECK(!on_failed_called_);
      CHECK(!not_expect_callback_);
  
      ++on_data_sent_count_;
      loop_->Quit();
    }
  
    void OnTrailersReceived(const spdy::Http2HeaderBlock& trailers) override {
      CHECK(!on_failed_called_);
      CHECK(!not_expect_callback_);
  
      trailers_received_ = true;
      trailers_ = trailers.Clone();
      loop_->Quit();
    }
  
    void OnFailed(int error) override {
      CHECK(!on_failed_called_);
      CHECK(!not_expect_callback_);
      CHECK_EQ(OK, error_);
      CHECK_NE(OK, error);
  
      on_failed_called_ = true;
      error_ = error;
      loop_->Quit();
    }
  
    void Start(const BidirectionalStreamRequestInfo* request_info,
               const NetLogWithSource& net_log,
               std::unique_ptr<QuicChromiumClientSession::Handle> session) {
      not_expect_callback_ = true;
      stream_ = std::make_unique<BidirectionalStreamQuicImpl>(std::move(session));
      stream_->Start(request_info, net_log, send_request_headers_automatically_,
                     this, nullptr, TRAFFIC_ANNOTATION_FOR_TESTS);
      not_expect_callback_ = false;
    }
  
    void SendRequestHeaders() {
      not_expect_callback_ = true;
      stream_->SendRequestHeaders();
      not_expect_callback_ = false;
    }
  
    void SendData(const scoped_refptr<IOBuffer>& data,
                  int length,
                  bool end_of_stream) {
      SendvData({data}, {length}, end_of_stream);
    }
  
    void SendvData(const std::vector<scoped_refptr<IOBuffer>>& data,
                   const std::vector<int>& lengths,
                   bool end_of_stream) {
      not_expect_callback_ = true;
      stream_->SendvData(data, lengths, end_of_stream);
      not_expect_callback_ = false;
    }
  
    // Waits until next Delegate callback.
    void WaitUntilNextCallback(DelegateMethod method) {
      ASSERT_FALSE(on_failed_called_);
      bool is_ready = is_ready_;
      bool headers_received = !response_headers_.empty();
      bool trailers_received = trailers_received_;
      int on_data_read_count = on_data_read_count_;
      int on_data_sent_count = on_data_sent_count_;
  
      loop_->Run();
      loop_ = std::make_unique<base::RunLoop>();
  
      EXPECT_EQ(method == kOnFailed, on_failed_called_);
      EXPECT_EQ(is_ready || (method == kOnStreamReady), is_ready_);
      EXPECT_EQ(headers_received || (method == kOnHeadersReceived),
                !response_headers_.empty());
      EXPECT_EQ(trailers_received || (method == kOnTrailersReceived),
                trailers_received_);
      EXPECT_EQ(on_data_read_count + (method == kOnDataRead ? 1 : 0),
                on_data_read_count_);
      EXPECT_EQ(on_data_sent_count + (method == kOnDataSent ? 1 : 0),
                on_data_sent_count_);
    }
  
    // Calls ReadData on the |stream_| and updates |data_received_|.
    int ReadData(CompletionOnceCallback callback) {
      not_expect_callback_ = true;
      int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
      not_expect_callback_ = false;
      if (rv > 0)
        data_received_.append(read_buf_->data(), rv);
      if (rv == ERR_IO_PENDING)
        callback_ = std::move(callback);
      return rv;
    }
  
    NextProto GetProtocol() const {
      if (stream_)
        return stream_->GetProtocol();
      return next_proto_;
    }
  
    int64_t GetTotalReceivedBytes() const {
      if (stream_)
        return stream_->GetTotalReceivedBytes();
      return received_bytes_;
    }
  
    int64_t GetTotalSentBytes() const {
      if (stream_)
        return stream_->GetTotalSentBytes();
      return sent_bytes_;
    }
  
    bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) {
      if (stream_)
        return stream_->GetLoadTimingInfo(load_timing_info);
      *load_timing_info = load_timing_info_;
      return has_load_timing_info_;
    }
  
    void DoNotSendRequestHeadersAutomatically() {
      send_request_headers_automatically_ = false;
    }
  
    // Deletes |stream_|.
    void DeleteStream() {
      next_proto_ = stream_->GetProtocol();
      received_bytes_ = stream_->GetTotalReceivedBytes();
      sent_bytes_ = stream_->GetTotalSentBytes();
      has_load_timing_info_ = stream_->GetLoadTimingInfo(&load_timing_info_);
      stream_.reset();
    }
  
    void set_trailers_expected(bool trailers_expected) {
      trailers_expected_ = trailers_expected;
    }
    // Const getters for internal states.
    const std::string& data_received() const { return data_received_; }
    int error() const { return error_; }
    const spdy::Http2HeaderBlock& response_headers() const {
      return response_headers_;
    }
    const spdy::Http2HeaderBlock& trailers() const { return trailers_; }
    int on_data_read_count() const { return on_data_read_count_; }
    int on_data_sent_count() const { return on_data_sent_count_; }
    bool on_failed_called() const { return on_failed_called_; }
    bool is_ready() const { return is_ready_; }
  
   protected:
    // Quits |loop_|.
    void QuitLoop() { loop_->Quit(); }
  
   private:
    std::unique_ptr<BidirectionalStreamQuicImpl> stream_;
    scoped_refptr<IOBuffer> read_buf_;
    int read_buf_len_;
    std::unique_ptr<base::OneShotTimer> timer_;
    std::string data_received_;
    std::unique_ptr<base::RunLoop> loop_;
    spdy::Http2HeaderBlock response_headers_;
    spdy::Http2HeaderBlock trailers_;
    NextProto next_proto_;
    int64_t received_bytes_;
    int64_t sent_bytes_;
    bool has_load_timing_info_;
    LoadTimingInfo load_timing_info_;
    int error_;
    int on_data_read_count_;
    int on_data_sent_count_;
    // This is to ensure that delegate callback is not invoked synchronously when
    // calling into |stream_|.
    bool not_expect_callback_;
    bool on_failed_called_;
    CompletionOnceCallback callback_;
    bool send_request_headers_automatically_;
    bool is_ready_;
    bool trailers_expected_;
    bool trailers_received_;
  
    DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
  };
  
  // A delegate that deletes the stream in a particular callback.
  class DeleteStreamDelegate : public TestDelegateBase {
   public:
    // Specifies in which callback the stream can be deleted.
    enum Phase {
      ON_STREAM_READY,
      ON_HEADERS_RECEIVED,
      ON_DATA_READ,
      ON_TRAILERS_RECEIVED,
      ON_FAILED,
    };
  
    DeleteStreamDelegate(IOBuffer* buf, int buf_len, Phase phase)
        : TestDelegateBase(buf, buf_len), phase_(phase) {}
    ~DeleteStreamDelegate() override {}
  
    void OnStreamReady(bool request_headers_sent) override {
      TestDelegateBase::OnStreamReady(request_headers_sent);
      if (phase_ == ON_STREAM_READY)
        DeleteStream();
    }
  
    void OnHeadersReceived(
        const spdy::Http2HeaderBlock& response_headers) override {
      // Make a copy of |response_headers| before the stream is deleted, since
      // the headers are owned by the stream.
      spdy::Http2HeaderBlock headers_copy = response_headers.Clone();
      if (phase_ == ON_HEADERS_RECEIVED)
        DeleteStream();
      TestDelegateBase::OnHeadersReceived(headers_copy);
    }
  
    void OnDataSent() override { NOTREACHED(); }
  
    void OnDataRead(int bytes_read) override {
      DCHECK_NE(ON_HEADERS_RECEIVED, phase_);
      if (phase_ == ON_DATA_READ)
        DeleteStream();
      TestDelegateBase::OnDataRead(bytes_read);
    }
  
    void OnTrailersReceived(const spdy::Http2HeaderBlock& trailers) override {
      DCHECK_NE(ON_HEADERS_RECEIVED, phase_);
      DCHECK_NE(ON_DATA_READ, phase_);
      // Make a copy of |response_headers| before the stream is deleted, since
      // the headers are owned by the stream.
      spdy::Http2HeaderBlock trailers_copy = trailers.Clone();
      if (phase_ == ON_TRAILERS_RECEIVED)
        DeleteStream();
      TestDelegateBase::OnTrailersReceived(trailers_copy);
    }
  
    void OnFailed(int error) override {
      DCHECK_EQ(ON_FAILED, phase_);
      DeleteStream();
      TestDelegateBase::OnFailed(error);
    }
  
   private:
    // Indicates in which callback the delegate should cancel or delete the
    // stream.
    Phase phase_;
  
    DISALLOW_COPY_AND_ASSIGN(DeleteStreamDelegate);
  };
  
  }  // namespace
  
  class BidirectionalStreamQuicImplTest
      : public ::testing::TestWithParam<TestParams>,
        public WithTaskEnvironment {
   protected:
    static const bool kFin = true;
    static const bool kIncludeVersion = true;
  
    // Holds a packet to be written to the wire, and the IO mode that should
    // be used by the mock socket when performing the write.
    struct PacketToWrite {
      PacketToWrite(IoMode mode, quic::QuicReceivedPacket* packet)
          : mode(mode), packet(packet) {}
      PacketToWrite(IoMode mode, int rv) : mode(mode), packet(nullptr), rv(rv) {}
      IoMode mode;
      quic::QuicReceivedPacket* packet;
      int rv;
    };
  
    BidirectionalStreamQuicImplTest()
        : version_(GetParam().version),
          client_headers_include_h2_stream_dependency_(
              GetParam().client_headers_include_h2_stream_dependency),
          crypto_config_(
              quic::test::crypto_test_utils::ProofVerifierForTesting()),
          read_buffer_(base::MakeRefCounted<IOBufferWithSize>(4096)),
          connection_id_(quic::test::TestConnectionId(2)),
          stream_id_(GetNthClientInitiatedBidirectionalStreamId(0)),
          client_maker_(version_,
                        connection_id_,
                        &clock_,
                        kDefaultServerHostName,
                        quic::Perspective::IS_CLIENT,
                        client_headers_include_h2_stream_dependency_),
          packet_number_(0),
          server_maker_(version_,
                        connection_id_,
                        &clock_,
                        kDefaultServerHostName,
                        quic::Perspective::IS_SERVER,
                        false),
          random_generator_(0),
          printer_(version_),
          destination_(kDefaultServerHostName, kDefaultServerPort) {
      quic::QuicEnableVersion(version_);
      FLAGS_quic_enable_http3_grease_randomness = false;
      IPAddress ip(192, 0, 2, 33);
      peer_addr_ = IPEndPoint(ip, 443);
      self_addr_ = IPEndPoint(ip, 8435);
      clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(20));
    }
  
    ~BidirectionalStreamQuicImplTest() {
      if (session_) {
        session_->CloseSessionOnError(
            ERR_ABORTED, quic::QUIC_INTERNAL_ERROR,
            quic::ConnectionCloseBehavior::SILENT_CLOSE);
      }
      for (size_t i = 0; i < writes_.size(); i++) {
        delete writes_[i].packet;
      }
    }
  
    void TearDown() override {
      if (socket_data_) {
        EXPECT_TRUE(socket_data_->AllReadDataConsumed());
        EXPECT_TRUE(socket_data_->AllWriteDataConsumed());
      }
    }
  
    // Adds a packet to the list of expected writes.
    void AddWrite(std::unique_ptr<quic::QuicReceivedPacket> packet) {
      writes_.push_back(PacketToWrite(SYNCHRONOUS, packet.release()));
    }
  
    // Adds a write error to the list of expected writes.
    void AddWriteError(IoMode mode, int rv) {
      writes_.push_back(PacketToWrite(mode, rv));
    }
  
    void ProcessPacket(std::unique_ptr<quic::QuicReceivedPacket> packet) {
      connection_->ProcessUdpPacket(ToQuicSocketAddress(self_addr_),
                                    ToQuicSocketAddress(peer_addr_), *packet);
    }
  
    // Configures the test fixture to use the list of expected writes.
    void Initialize() {
      crypto_client_stream_factory_.set_handshake_mode(
          MockCryptoClientStream::ZERO_RTT);
      mock_writes_ = std::make_unique<MockWrite[]>(writes_.size());
      for (size_t i = 0; i < writes_.size(); i++) {
        if (writes_[i].packet == nullptr) {
          mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].rv, i);
        } else {
          mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].packet->data(),
                                      writes_[i].packet->length());
        }
      }
  
      socket_data_ = std::make_unique<StaticSocketDataProvider>(
          base::span<MockRead>(),
          base::make_span(mock_writes_.get(), writes_.size()));
      socket_data_->set_printer(&printer_);
  
      std::unique_ptr<MockUDPClientSocket> socket(new MockUDPClientSocket(
          socket_data_.get(), net_log().bound().net_log()));
      socket->Connect(peer_addr_);
      runner_ = new TestTaskRunner(&clock_);
      helper_ = std::make_unique<QuicChromiumConnectionHelper>(
          &clock_, &random_generator_);
      alarm_factory_ =
          std::make_unique<QuicChromiumAlarmFactory>(runner_.get(), &clock_);
      connection_ = new quic::QuicConnection(
          connection_id_, quic::QuicSocketAddress(),
          ToQuicSocketAddress(peer_addr_), helper_.get(), alarm_factory_.get(),
          new QuicChromiumPacketWriter(socket.get(), runner_.get()),
          true /* owns_writer */, quic::Perspective::IS_CLIENT,
          quic::test::SupportedVersions(version_));
      if (connection_->version().KnowsWhichDecrypterToUse()) {
        connection_->InstallDecrypter(
            quic::ENCRYPTION_FORWARD_SECURE,
            std::make_unique<quic::NullDecrypter>(quic::Perspective::IS_CLIENT));
      }
      base::TimeTicks dns_end = base::TimeTicks::Now();
      base::TimeTicks dns_start = dns_end - base::TimeDelta::FromMilliseconds(1);
  
      session_ = std::make_unique<QuicChromiumClientSession>(
          connection_, std::move(socket),
          /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_,
          &transport_security_state_, /*ssl_config_service=*/nullptr,
          base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
          QuicSessionKey(kDefaultServerHostName, kDefaultServerPort,
                         PRIVACY_MODE_DISABLED, SocketTag(),
                         NetworkIsolationKey(), SecureDnsPolicy::kAllow),
          /*require_confirmation=*/false,
          /*migrate_session_early_v2=*/false,
          /*migrate_session_on_network_change_v2=*/false,
          /*default_network=*/NetworkChangeNotifier::kInvalidNetworkHandle,
          quic::QuicTime::Delta::FromMilliseconds(
              kDefaultRetransmittableOnWireTimeout.InMilliseconds()),
          /*migrate_idle_session=*/false, /*allow_port_migration=*/false,
          kDefaultIdleSessionMigrationPeriod, kMaxTimeOnNonDefaultNetwork,
          kMaxMigrationsToNonDefaultNetworkOnWriteError,
          kMaxMigrationsToNonDefaultNetworkOnPathDegrading,
          kQuicYieldAfterPacketsRead,
          quic::QuicTime::Delta::FromMilliseconds(
              kQuicYieldAfterDurationMilliseconds),
          /*go_away_on_path_degrading*/ false,
          client_headers_include_h2_stream_dependency_, /*cert_verify_flags=*/0,
          quic::test::DefaultQuicConfig(),
          std::make_unique<TestQuicCryptoClientConfigHandle>(&crypto_config_),
          "CONNECTION_UNKNOWN", dns_start, dns_end,
          std::make_unique<quic::QuicClientPushPromiseIndex>(), nullptr,
          base::DefaultTickClock::GetInstance(),
          base::ThreadTaskRunnerHandle::Get().get(),
          /*socket_performance_watcher=*/nullptr, net_log().bound().net_log());
      session_->Initialize();
  
      // Blackhole QPACK decoder stream instead of constructing mock writes.
      if (VersionUsesHttp3(version_.transport_version)) {
        session_->qpack_decoder()->set_qpack_stream_sender_delegate(
            &noop_qpack_stream_sender_delegate_);
      }
  
      TestCompletionCallback callback;
      session_->CryptoConnect(callback.callback());
      EXPECT_TRUE(session_->IsEncryptionEstablished());
    }
  
    void ConfirmHandshake() {
      crypto_client_stream_factory_.last_stream()
          ->NotifySessionOneRttKeyAvailable();
    }
  
    void SetRequest(const std::string& method,
                    const std::string& path,
                    RequestPriority priority) {
      request_headers_ = client_maker_.GetRequestHeaders(method, "http", path);
    }
  
    spdy::Http2HeaderBlock ConstructResponseHeaders(
        const std::string& response_code) {
      return server_maker_.GetResponseHeaders(response_code);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructServerDataPacket(
        uint64_t packet_number,
        bool should_include_version,
        bool fin,
        absl::string_view data) {
      std::unique_ptr<quic::QuicReceivedPacket> packet(
          server_maker_.MakeDataPacket(packet_number, stream_id_,
                                       should_include_version, fin, data));
      DVLOG(2) << "packet(" << packet_number << "): " << std::endl
               << quiche::QuicheTextUtils::HexDump(packet->AsStringPiece());
      return packet;
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructClientDataPacket(
        bool should_include_version,
        bool fin,
        absl::string_view data) {
      return client_maker_.MakeDataPacket(++packet_number_, stream_id_,
                                          should_include_version, fin, data);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructRequestHeadersPacket(
        bool fin,
        RequestPriority request_priority,
        size_t* spdy_headers_frame_length) {
      return ConstructRequestHeadersPacketInner(stream_id_, fin, request_priority,
                                                spdy_headers_frame_length);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructRequestHeadersPacketInner(
        quic::QuicStreamId stream_id,
        bool fin,
        RequestPriority request_priority,
        size_t* spdy_headers_frame_length) {
      return ConstructRequestHeadersPacketInner(stream_id, fin, request_priority,
                                                0, spdy_headers_frame_length);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructRequestHeadersPacketInner(
        quic::QuicStreamId stream_id,
        bool fin,
        RequestPriority request_priority,
        quic::QuicStreamId parent_stream_id,
        size_t* spdy_headers_frame_length) {
      spdy::SpdyPriority priority =
          ConvertRequestPriorityToQuicPriority(request_priority);
      std::unique_ptr<quic::QuicReceivedPacket> packet(
          client_maker_.MakeRequestHeadersPacket(
              ++packet_number_, stream_id, kIncludeVersion, fin, priority,
              std::move(request_headers_), parent_stream_id,
              spdy_headers_frame_length));
      DVLOG(2) << "packet(" << packet_number_ << "): " << std::endl
               << quiche::QuicheTextUtils::HexDump(packet->AsStringPiece());
      return packet;
    }
  
    std::unique_ptr<quic::QuicReceivedPacket>
    ConstructRequestHeadersAndMultipleDataFramesPacket(
        bool fin,
        RequestPriority request_priority,
        size_t* spdy_headers_frame_length,
        const std::vector<std::string>& data) {
      spdy::SpdyPriority priority =
          ConvertRequestPriorityToQuicPriority(request_priority);
      std::unique_ptr<quic::QuicReceivedPacket> packet(
          client_maker_.MakeRequestHeadersAndMultipleDataFramesPacket(
              ++packet_number_, stream_id_, kIncludeVersion, fin, priority,
              std::move(request_headers_), 0, spdy_headers_frame_length, data));
      DVLOG(2) << "packet(" << packet_number_ << "): " << std::endl
               << quiche::QuicheTextUtils::HexDump(packet->AsStringPiece());
      return packet;
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructResponseHeadersPacket(
        uint64_t packet_number,
        bool fin,
        spdy::Http2HeaderBlock response_headers,
        size_t* spdy_headers_frame_length) {
      return ConstructResponseHeadersPacketInner(packet_number, stream_id_, fin,
                                                 std::move(response_headers),
                                                 spdy_headers_frame_length);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructResponseHeadersPacketInner(
        uint64_t packet_number,
        quic::QuicStreamId stream_id,
        bool fin,
        spdy::Http2HeaderBlock response_headers,
        size_t* spdy_headers_frame_length) {
      return server_maker_.MakeResponseHeadersPacket(
          packet_number, stream_id, !kIncludeVersion, fin,
          std::move(response_headers), spdy_headers_frame_length);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructResponseTrailersPacket(
        uint64_t packet_number,
        bool fin,
        spdy::Http2HeaderBlock trailers,
        size_t* spdy_headers_frame_length) {
      return server_maker_.MakeResponseHeadersPacket(
          packet_number, stream_id_, !kIncludeVersion, fin, std::move(trailers),
          spdy_headers_frame_length);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructClientRstStreamPacket() {
      return ConstructRstStreamCancelledPacket(++packet_number_, !kIncludeVersion,
                                               &client_maker_);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructServerRstStreamPacket(
        uint64_t packet_number) {
      return ConstructRstStreamCancelledPacket(packet_number, !kIncludeVersion,
                                               &server_maker_);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket>
    ConstructClientEarlyRstStreamPacket() {
      return ConstructRstStreamCancelledPacket(++packet_number_, kIncludeVersion,
                                               &client_maker_);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructRstStreamCancelledPacket(
        uint64_t packet_number,
        bool include_version,
        QuicTestPacketMaker* maker) {
      std::unique_ptr<quic::QuicReceivedPacket> packet(maker->MakeRstPacket(
          packet_number, include_version, stream_id_, quic::QUIC_STREAM_CANCELLED,
          /*include_stop_sending_if_v99=*/true));
      DVLOG(2) << "packet(" << packet_number << "): " << std::endl
               << quiche::QuicheTextUtils::HexDump(packet->AsStringPiece());
      return packet;
    }
  
    std::unique_ptr<quic::QuicReceivedPacket>
    ConstructClientAckAndRstStreamPacket(uint64_t largest_received,
                                         uint64_t smallest_received) {
      return client_maker_.MakeAckAndRstPacket(
          ++packet_number_, !kIncludeVersion, stream_id_,
          quic::QUIC_STREAM_CANCELLED, largest_received, smallest_received);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructAckAndDataPacket(
        uint64_t packet_number,
        bool should_include_version,
        uint64_t largest_received,
        uint64_t smallest_received,
        bool fin,
        absl::string_view data,
        QuicTestPacketMaker* maker) {
      std::unique_ptr<quic::QuicReceivedPacket> packet(
          maker->MakeAckAndDataPacket(packet_number, should_include_version,
                                      stream_id_, largest_received,
                                      smallest_received, fin, data));
      DVLOG(2) << "packet(" << packet_number << "): " << std::endl
               << quiche::QuicheTextUtils::HexDump(packet->AsStringPiece());
      return packet;
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructClientAckPacket(
        uint64_t largest_received,
        uint64_t smallest_received) {
      return client_maker_.MakeAckPacket(++packet_number_, largest_received,
                                         smallest_received);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructServerAckPacket(
        uint64_t packet_number,
        uint64_t largest_received,
        uint64_t smallest_received,
        uint64_t least_unacked) {
      return server_maker_.MakeAckPacket(packet_number, largest_received,
                                         smallest_received, least_unacked);
    }
  
    std::unique_ptr<quic::QuicReceivedPacket> ConstructInitialSettingsPacket() {
      return client_maker_.MakeInitialSettingsPacket(++packet_number_);
    }
  
    void ExpectLoadTimingValid(const LoadTimingInfo& load_timing_info,
                               bool session_reused) {
      EXPECT_EQ(session_reused, load_timing_info.socket_reused);
  
      if (session_reused) {
        ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
      } else {
        ExpectConnectTimingHasTimes(
            load_timing_info.connect_timing,
            CONNECT_TIMING_HAS_SSL_TIMES | CONNECT_TIMING_HAS_DNS_TIMES);
      }
      ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
    }
  
    const RecordingBoundTestNetLog& net_log() const { return net_log_; }
  
    QuicChromiumClientSession* session() const { return session_.get(); }
  
    quic::QuicStreamId GetNthClientInitiatedBidirectionalStreamId(int n) {
      return quic::test::GetNthClientInitiatedBidirectionalStreamId(
          version_.transport_version, n);
    }
  
    std::string ConstructDataHeader(size_t body_len) {
      if (!version_.UsesHttp3()) {
        return "";
      }
      quic::QuicBuffer buffer = quic::HttpEncoder::SerializeDataFrameHeader(
          body_len, quic::SimpleBufferAllocator::Get());
      return std::string(buffer.data(), buffer.size());
    }
  
   protected:
    QuicFlagSaver saver_;
    const quic::ParsedQuicVersion version_;
    const bool client_headers_include_h2_stream_dependency_;
    RecordingBoundTestNetLog net_log_;
    scoped_refptr<TestTaskRunner> runner_;
    std::unique_ptr<MockWrite[]> mock_writes_;
    quic::MockClock clock_;
    quic::QuicConnection* connection_;
    std::unique_ptr<QuicChromiumConnectionHelper> helper_;
    std::unique_ptr<QuicChromiumAlarmFactory> alarm_factory_;
    TransportSecurityState transport_security_state_;
    std::unique_ptr<QuicChromiumClientSession> session_;
    quic::QuicCryptoClientConfig crypto_config_;
    HttpRequestHeaders headers_;
    HttpResponseInfo response_;
    scoped_refptr<IOBufferWithSize> read_buffer_;
    spdy::Http2HeaderBlock request_headers_;
    const quic::QuicConnectionId connection_id_;
    const quic::QuicStreamId stream_id_;
    QuicTestPacketMaker client_maker_;
    uint64_t packet_number_;
    QuicTestPacketMaker server_maker_;
    IPEndPoint self_addr_;
    IPEndPoint peer_addr_;
    quic::test::MockRandom random_generator_;
    QuicPacketPrinter printer_;
    MockCryptoClientStreamFactory crypto_client_stream_factory_;
    std::unique_ptr<StaticSocketDataProvider> socket_data_;
    std::vector<PacketToWrite> writes_;
    HostPortPair destination_;
    quic::test::NoopQpackStreamSenderDelegate noop_qpack_stream_sender_delegate_;
  };
  
  INSTANTIATE_TEST_SUITE_P(Version,
                           BidirectionalStreamQuicImplTest,
                           ::testing::ValuesIn(GetTestParams()),
                           ::testing::PrintToStringParamName());
  
  TEST_P(BidirectionalStreamQuicImplTest, GetRequest) {
    SetRequest("GET", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructClientAckPacket(3, 1));
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "GET";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = true;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->set_trailers_expected(true);
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    delegate->WaitUntilNextCallback(kOnStreamReady);
    ConfirmHandshake();
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
  
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    LoadTimingInfo load_timing_info;
    EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info));
    ExpectLoadTimingValid(load_timing_info, /*session_reused=*/false);
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
    const char kResponseBody[] = "Hello world!";
    // Server sends data.
    std::string header = ConstructDataHeader(strlen(kResponseBody));
    ProcessPacket(ConstructServerDataPacket(3, !kIncludeVersion, !kFin,
                                            header + kResponseBody));
    EXPECT_EQ(12, cb.WaitForResult());
  
    EXPECT_EQ(std::string(kResponseBody), delegate->data_received());
    TestCompletionCallback cb2;
    EXPECT_THAT(delegate->ReadData(cb2.callback()), IsError(ERR_IO_PENDING));
  
    spdy::Http2HeaderBlock trailers;
    size_t spdy_trailers_frame_length;
    trailers["foo"] = "bar";
    if (!quic::VersionUsesHttp3(version_.transport_version)) {
      trailers[quic::kFinalOffsetHeaderKey] =
          base::NumberToString(strlen(kResponseBody));
    }
    // Server sends trailers.
    ProcessPacket(ConstructResponseTrailersPacket(4, kFin, trailers.Clone(),
                                                  &spdy_trailers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnTrailersReceived);
    EXPECT_THAT(cb2.WaitForResult(), IsOk());
    trailers.erase(quic::kFinalOffsetHeaderKey);
    EXPECT_EQ(trailers, delegate->trailers());
  
    EXPECT_THAT(delegate->ReadData(cb2.callback()), IsOk());
    base::RunLoop().RunUntilIdle();
  
    EXPECT_EQ(2, delegate->on_data_read_count());
    EXPECT_EQ(0, delegate->on_data_sent_count());
    EXPECT_EQ(kProtoQUIC, delegate->GetProtocol());
    EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
              delegate->GetTotalSentBytes());
    EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
                                   strlen(kResponseBody) + header.length() +
                                   spdy_trailers_frame_length),
              delegate->GetTotalReceivedBytes());
    // Check that NetLog was filled as expected.
    auto entries = net_log().GetEntries();
    size_t pos = ExpectLogContainsSomewhere(
        entries, /*min_offset=*/0,
        NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
        NetLogEventPhase::NONE);
    pos = ExpectLogContainsSomewhere(
        entries, /*min_offset=*/pos,
        NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
        NetLogEventPhase::NONE);
    ExpectLogContainsSomewhere(
        entries, /*min_offset=*/pos,
        NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
        NetLogEventPhase::NONE);
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, LoadTimingTwoRequests) {
    SetRequest("GET", "/", DEFAULT_PRIORITY);
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), kFin, DEFAULT_PRIORITY,
        nullptr));
    // SetRequest() again for second request as |request_headers_| was moved.
    SetRequest("GET", "/", DEFAULT_PRIORITY);
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(1), kFin, DEFAULT_PRIORITY,
        GetNthClientInitiatedBidirectionalStreamId(0), nullptr));
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructClientAckPacket(3, 1));
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "GET";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = true;
    request.priority = DEFAULT_PRIORITY;
  
    // Start first request.
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
  
    // Start second request.
    scoped_refptr<IOBuffer> read_buffer2 =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate2(
        new TestDelegateBase(read_buffer2.get(), kReadBufferSize));
    delegate2->Start(&request, net_log().bound(),
                     session()->CreateHandle(destination_));
  
    delegate->WaitUntilNextCallback(kOnStreamReady);
    delegate2->WaitUntilNextCallback(kOnStreamReady);
  
    ConfirmHandshake();
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    ProcessPacket(ConstructResponseHeadersPacketInner(
        2, GetNthClientInitiatedBidirectionalStreamId(0), kFin,
        ConstructResponseHeaders("200"), nullptr));
  
    ProcessPacket(ConstructResponseHeadersPacketInner(
        3, GetNthClientInitiatedBidirectionalStreamId(1), kFin,
        ConstructResponseHeaders("200"), nullptr));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    delegate2->WaitUntilNextCallback(kOnHeadersReceived);
  
    LoadTimingInfo load_timing_info;
    EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info));
    LoadTimingInfo load_timing_info2;
    EXPECT_TRUE(delegate2->GetLoadTimingInfo(&load_timing_info2));
    ExpectLoadTimingValid(load_timing_info, /*session_reused=*/false);
    ExpectLoadTimingValid(load_timing_info2, /*session_reused=*/true);
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
    EXPECT_EQ("200", delegate2->response_headers().find(":status")->second);
    // No response body. ReadData() should return OK synchronously.
    TestCompletionCallback dummy_callback;
    EXPECT_EQ(OK, delegate->ReadData(dummy_callback.callback()));
    EXPECT_EQ(OK, delegate2->ReadData(dummy_callback.callback()));
  }
  
  // Tests that when request headers are not delayed, only data buffers are
  // coalesced.
  TEST_P(BidirectionalStreamQuicImplTest, CoalesceDataBuffersNotHeadersFrame) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    const std::string kBody1 = "here are some data";
    const std::string kBody2 = "data keep coming";
    std::string header = ConstructDataHeader(kBody1.length());
    std::string header2 = ConstructDataHeader(kBody2.length());
    std::vector<std::string> two_writes = {kBody1, kBody2};
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    if (!version_.UsesHttp3()) {
      AddWrite(
          ConstructClientDataPacket(kIncludeVersion, !kFin, kBody1 + kBody2));
    } else {
      AddWrite(ConstructClientDataPacket(kIncludeVersion, !kFin,
                                         header + kBody1 + header2 + kBody2));
    }
  
    // Ack server's data packet.
    AddWrite(ConstructClientAckPacket(3, 1));
    const std::string kBody3 = "hello there";
    const std::string kBody4 = "another piece of small data";
    const std::string kBody5 = "really small";
    std::string header3 = ConstructDataHeader(kBody3.length());
    std::string header4 = ConstructDataHeader(kBody4.length());
    std::string header5 = ConstructDataHeader(kBody5.length());
    if (!version_.UsesHttp3()) {
      AddWrite(ConstructClientDataPacket(!kIncludeVersion, kFin,
                                         kBody3 + kBody4 + kBody5));
    } else {
      AddWrite(ConstructClientDataPacket(
          !kIncludeVersion, kFin,
          header3 + kBody3 + header4 + kBody4 + header5 + kBody5));
    }
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->DoNotSendRequestHeadersAutomatically();
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    EXPECT_FALSE(delegate->is_ready());
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
    EXPECT_TRUE(delegate->is_ready());
  
    // Sends request headers separately, which causes them to be sent in a
    // separate packet.
    delegate->SendRequestHeaders();
    // Send a Data packet.
    scoped_refptr<StringIOBuffer> buf1 =
        base::MakeRefCounted<StringIOBuffer>(kBody1);
    scoped_refptr<StringIOBuffer> buf2 =
        base::MakeRefCounted<StringIOBuffer>(kBody2);
  
    std::vector<int> lengths = {buf1->size(), buf2->size()};
    delegate->SendvData({buf1, buf2}, lengths, !kFin);
    delegate->WaitUntilNextCallback(kOnDataSent);
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
    const char kResponseBody[] = "Hello world!";
    std::string header6 = ConstructDataHeader(strlen(kResponseBody));
    // Server sends data.
    ProcessPacket(ConstructServerDataPacket(3, !kIncludeVersion, !kFin,
                                            header6 + kResponseBody));
  
    EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
  
    // Send a second Data packet.
    scoped_refptr<StringIOBuffer> buf3 =
        base::MakeRefCounted<StringIOBuffer>(kBody3);
    scoped_refptr<StringIOBuffer> buf4 =
        base::MakeRefCounted<StringIOBuffer>(kBody4);
    scoped_refptr<StringIOBuffer> buf5 =
        base::MakeRefCounted<StringIOBuffer>(kBody5);
  
    delegate->SendvData({buf3, buf4, buf5},
                        {buf3->size(), buf4->size(), buf5->size()}, kFin);
    delegate->WaitUntilNextCallback(kOnDataSent);
  
    size_t spdy_trailers_frame_length;
    spdy::Http2HeaderBlock trailers;
    trailers["foo"] = "bar";
    if (!quic::VersionUsesHttp3(version_.transport_version)) {
      trailers[quic::kFinalOffsetHeaderKey] =
          base::NumberToString(strlen(kResponseBody));
    }
    // Server sends trailers.
    ProcessPacket(ConstructResponseTrailersPacket(4, kFin, trailers.Clone(),
                                                  &spdy_trailers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnTrailersReceived);
    trailers.erase(quic::kFinalOffsetHeaderKey);
    EXPECT_EQ(trailers, delegate->trailers());
    EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk());
  
    EXPECT_EQ(1, delegate->on_data_read_count());
    EXPECT_EQ(2, delegate->on_data_sent_count());
    EXPECT_EQ(kProtoQUIC, delegate->GetProtocol());
    EXPECT_EQ(static_cast<int64_t>(
                  spdy_request_headers_frame_length + kBody1.length() +
                  kBody2.length() + kBody3.length() + kBody4.length() +
                  kBody5.length() + header.length() + header2.length() +
                  header3.length() + header4.length() + header5.length()),
              delegate->GetTotalSentBytes());
    EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
                                   strlen(kResponseBody) + header6.length() +
                                   spdy_trailers_frame_length),
              delegate->GetTotalReceivedBytes());
  }
  
  // Tests that when request headers are delayed, SendData triggers coalescing of
  // request headers with data buffers.
  TEST_P(BidirectionalStreamQuicImplTest,
         SendDataCoalesceDataBufferAndHeaderFrame) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    const char kBody1[] = "here are some data";
    std::string header = ConstructDataHeader(strlen(kBody1));
    if (version_.UsesHttp3()) {
      AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket(
          !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length,
          {header, kBody1}));
    } else {
      AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket(
          !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length, {kBody1}));
    }
  
    // Ack server's data packet.
    AddWrite(ConstructClientAckPacket(3, 1));
    const char kBody2[] = "really small";
    std::string header2 = ConstructDataHeader(strlen(kBody2));
    if (version_.UsesHttp3()) {
      AddWrite(ConstructClientDataPacket(!kIncludeVersion, kFin,
                                         header2 + std::string(kBody2)));
    } else {
      AddWrite(ConstructClientDataPacket(!kIncludeVersion, kFin, kBody2));
    }
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->DoNotSendRequestHeadersAutomatically();
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Send a Data packet.
    scoped_refptr<StringIOBuffer> buf1 =
        base::MakeRefCounted<StringIOBuffer>(kBody1);
  
    delegate->SendData(buf1, buf1->size(), false);
    delegate->WaitUntilNextCallback(kOnDataSent);
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
    const char kResponseBody[] = "Hello world!";
    // Server sends data.
    std::string header3 = ConstructDataHeader(strlen(kResponseBody));
    ProcessPacket(ConstructServerDataPacket(3, !kIncludeVersion, !kFin,
                                            header3 + kResponseBody));
  
    EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
  
    // Send a second Data packet.
    scoped_refptr<StringIOBuffer> buf2 =
        base::MakeRefCounted<StringIOBuffer>(kBody2);
  
    delegate->SendData(buf2, buf2->size(), true);
    delegate->WaitUntilNextCallback(kOnDataSent);
  
    size_t spdy_trailers_frame_length;
    spdy::Http2HeaderBlock trailers;
    trailers["foo"] = "bar";
    if (!quic::VersionUsesHttp3(version_.transport_version)) {
      trailers[quic::kFinalOffsetHeaderKey] =
          base::NumberToString(strlen(kResponseBody));
    }
    // Server sends trailers.
    ProcessPacket(ConstructResponseTrailersPacket(4, kFin, trailers.Clone(),
                                                  &spdy_trailers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnTrailersReceived);
    trailers.erase(quic::kFinalOffsetHeaderKey);
    EXPECT_EQ(trailers, delegate->trailers());
    EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk());
  
    EXPECT_EQ(1, delegate->on_data_read_count());
    EXPECT_EQ(2, delegate->on_data_sent_count());
    EXPECT_EQ(kProtoQUIC, delegate->GetProtocol());
    EXPECT_EQ(
        static_cast<int64_t>(spdy_request_headers_frame_length + strlen(kBody1) +
                             strlen(kBody2) + header.length() + header2.length()),
        delegate->GetTotalSentBytes());
    EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
                                   strlen(kResponseBody) + header3.length() +
                                   spdy_trailers_frame_length),
              delegate->GetTotalReceivedBytes());
  }
  
  // Tests that when request headers are delayed, SendvData triggers coalescing of
  // request headers with data buffers.
  TEST_P(BidirectionalStreamQuicImplTest,
         SendvDataCoalesceDataBuffersAndHeaderFrame) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    const std::string kBody1 = "here are some data";
    const std::string kBody2 = "data keep coming";
    std::string header = ConstructDataHeader(kBody1.length());
    std::string header2 = ConstructDataHeader(kBody2.length());
  
    if (version_.UsesHttp3()) {
      AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket(
          !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length,
          {header + kBody1 + header2 + kBody2}));
    } else {
      AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket(
          !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length,
          {kBody1 + kBody2}));
    }
  
    // Ack server's data packet.
    AddWrite(ConstructClientAckPacket(3, 1));
    const std::string kBody3 = "hello there";
    const std::string kBody4 = "another piece of small data";
    const std::string kBody5 = "really small";
    std::string header3 = ConstructDataHeader(kBody3.length());
    std::string header4 = ConstructDataHeader(kBody4.length());
    std::string header5 = ConstructDataHeader(kBody5.length());
    if (version_.UsesHttp3()) {
      AddWrite(ConstructClientDataPacket(
          !kIncludeVersion, kFin,
          header3 + kBody3 + header4 + kBody4 + header5 + kBody5));
    } else {
      AddWrite(ConstructClientDataPacket(!kIncludeVersion, kFin,
                                         kBody3 + kBody4 + kBody5));
    }
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->DoNotSendRequestHeadersAutomatically();
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Send a Data packet.
    scoped_refptr<StringIOBuffer> buf1 =
        base::MakeRefCounted<StringIOBuffer>(kBody1);
    scoped_refptr<StringIOBuffer> buf2 =
        base::MakeRefCounted<StringIOBuffer>(kBody2);
  
    std::vector<int> lengths = {buf1->size(), buf2->size()};
    delegate->SendvData({buf1, buf2}, lengths, !kFin);
    delegate->WaitUntilNextCallback(kOnDataSent);
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
    const char kResponseBody[] = "Hello world!";
    std::string header6 = ConstructDataHeader(strlen(kResponseBody));
    // Server sends data.
    ProcessPacket(ConstructServerDataPacket(3, !kIncludeVersion, !kFin,
                                            header6 + kResponseBody));
  
    EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
  
    // Send a second Data packet.
    scoped_refptr<StringIOBuffer> buf3 =
        base::MakeRefCounted<StringIOBuffer>(kBody3);
    scoped_refptr<StringIOBuffer> buf4 =
        base::MakeRefCounted<StringIOBuffer>(kBody4);
    scoped_refptr<StringIOBuffer> buf5 =
        base::MakeRefCounted<StringIOBuffer>(kBody5);
  
    delegate->SendvData({buf3, buf4, buf5},
                        {buf3->size(), buf4->size(), buf5->size()}, kFin);
    delegate->WaitUntilNextCallback(kOnDataSent);
  
    size_t spdy_trailers_frame_length;
    spdy::Http2HeaderBlock trailers;
    trailers["foo"] = "bar";
    if (!quic::VersionUsesHttp3(version_.transport_version)) {
      trailers[quic::kFinalOffsetHeaderKey] =
          base::NumberToString(strlen(kResponseBody));
    }
    // Server sends trailers.
    ProcessPacket(ConstructResponseTrailersPacket(4, kFin, trailers.Clone(),
                                                  &spdy_trailers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnTrailersReceived);
    trailers.erase(quic::kFinalOffsetHeaderKey);
    EXPECT_EQ(trailers, delegate->trailers());
    EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk());
  
    EXPECT_EQ(1, delegate->on_data_read_count());
    EXPECT_EQ(2, delegate->on_data_sent_count());
    EXPECT_EQ(kProtoQUIC, delegate->GetProtocol());
    EXPECT_EQ(static_cast<int64_t>(
                  spdy_request_headers_frame_length + kBody1.length() +
                  kBody2.length() + kBody3.length() + kBody4.length() +
                  kBody5.length() + header.length() + header2.length() +
                  header3.length() + header4.length() + header5.length()),
              delegate->GetTotalSentBytes());
    EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
                                   strlen(kResponseBody) + header6.length() +
                                   spdy_trailers_frame_length),
              delegate->GetTotalReceivedBytes());
  }
  
  // Tests that when request headers are delayed and SendData triggers the
  // headers to be sent, if that write fails the stream does not crash.
  TEST_P(BidirectionalStreamQuicImplTest,
         SendDataWriteErrorCoalesceDataBufferAndHeaderFrame) {
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    AddWriteError(SYNCHRONOUS, ERR_CONNECTION_REFUSED);
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
    request.extra_headers.SetHeader("cookie", std::string(2048, 'A'));
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate(
        read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_FAILED));
    delegate->DoNotSendRequestHeadersAutomatically();
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Attempt to send the headers and data.
    const char kBody1[] = "here are some data";
    scoped_refptr<StringIOBuffer> buf1 =
        base::MakeRefCounted<StringIOBuffer>(kBody1);
    delegate->SendData(buf1, buf1->size(), !kFin);
  
    delegate->WaitUntilNextCallback(kOnFailed);
  }
  
  // Tests that when request headers are delayed and SendvData triggers the
  // headers to be sent, if that write fails the stream does not crash.
  TEST_P(BidirectionalStreamQuicImplTest,
         SendvDataWriteErrorCoalesceDataBufferAndHeaderFrame) {
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    AddWriteError(SYNCHRONOUS, ERR_CONNECTION_REFUSED);
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
    request.extra_headers.SetHeader("cookie", std::string(2048, 'A'));
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate(
        read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_FAILED));
    delegate->DoNotSendRequestHeadersAutomatically();
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Attempt to send the headers and data.
    const char kBody1[] = "here are some data";
    const char kBody2[] = "data keep coming";
    scoped_refptr<StringIOBuffer> buf1 =
        base::MakeRefCounted<StringIOBuffer>(kBody1);
    scoped_refptr<StringIOBuffer> buf2 =
        base::MakeRefCounted<StringIOBuffer>(kBody2);
    std::vector<int> lengths = {buf1->size(), buf2->size()};
    delegate->SendvData({buf1, buf2}, lengths, !kFin);
  
    delegate->WaitUntilNextCallback(kOnFailed);
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, PostRequest) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    std::string header = ConstructDataHeader(strlen(kUploadData));
    if (version_.UsesHttp3()) {
      AddWrite(ConstructClientDataPacket(kIncludeVersion, kFin,
                                         header + std::string(kUploadData)));
    } else {
      AddWrite(ConstructClientDataPacket(kIncludeVersion, kFin, kUploadData));
    }
  
    AddWrite(ConstructClientAckPacket(3, 1));
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Send a DATA frame.
    scoped_refptr<StringIOBuffer> buf =
        base::MakeRefCounted<StringIOBuffer>(kUploadData);
  
    delegate->SendData(buf, buf->size(), true);
    delegate->WaitUntilNextCallback(kOnDataSent);
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
    const char kResponseBody[] = "Hello world!";
    std::string header2 = ConstructDataHeader(strlen(kResponseBody));
    // Server sends data.
    ProcessPacket(ConstructServerDataPacket(3, !kIncludeVersion, !kFin,
                                            header2 + kResponseBody));
  
    EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
  
    size_t spdy_trailers_frame_length;
    spdy::Http2HeaderBlock trailers;
    trailers["foo"] = "bar";
    if (!quic::VersionUsesHttp3(version_.transport_version)) {
      trailers[quic::kFinalOffsetHeaderKey] =
          base::NumberToString(strlen(kResponseBody));
    }
    // Server sends trailers.
    ProcessPacket(ConstructResponseTrailersPacket(4, kFin, trailers.Clone(),
                                                  &spdy_trailers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnTrailersReceived);
    trailers.erase(quic::kFinalOffsetHeaderKey);
    EXPECT_EQ(trailers, delegate->trailers());
    EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk());
  
    EXPECT_EQ(1, delegate->on_data_read_count());
    EXPECT_EQ(1, delegate->on_data_sent_count());
    EXPECT_EQ(kProtoQUIC, delegate->GetProtocol());
    EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
                                   strlen(kUploadData) + header.length()),
              delegate->GetTotalSentBytes());
    EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
                                   strlen(kResponseBody) + header2.length() +
                                   spdy_trailers_frame_length),
              delegate->GetTotalReceivedBytes());
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, EarlyDataOverrideRequest) {
    SetRequest("PUT", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructClientAckPacket(3, 1));
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "PUT";
    request.allow_early_data_override = true;
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = true;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->set_trailers_expected(true);
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    delegate->WaitUntilNextCallback(kOnStreamReady);
    ConfirmHandshake();
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
  
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    LoadTimingInfo load_timing_info;
    EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info));
    ExpectLoadTimingValid(load_timing_info, /*session_reused=*/false);
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
    const char kResponseBody[] = "Hello world!";
    // Server sends data.
    std::string header = ConstructDataHeader(strlen(kResponseBody));
    ProcessPacket(ConstructServerDataPacket(3, !kIncludeVersion, !kFin,
                                            header + kResponseBody));
    EXPECT_EQ(12, cb.WaitForResult());
  
    EXPECT_EQ(std::string(kResponseBody), delegate->data_received());
    TestCompletionCallback cb2;
    EXPECT_THAT(delegate->ReadData(cb2.callback()), IsError(ERR_IO_PENDING));
  
    spdy::Http2HeaderBlock trailers;
    size_t spdy_trailers_frame_length;
    trailers["foo"] = "bar";
    if (!quic::VersionUsesHttp3(version_.transport_version)) {
      trailers[quic::kFinalOffsetHeaderKey] =
          base::NumberToString(strlen(kResponseBody));
    }
    // Server sends trailers.
    ProcessPacket(ConstructResponseTrailersPacket(4, kFin, trailers.Clone(),
                                                  &spdy_trailers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnTrailersReceived);
    EXPECT_THAT(cb2.WaitForResult(), IsOk());
    trailers.erase(quic::kFinalOffsetHeaderKey);
    EXPECT_EQ(trailers, delegate->trailers());
  
    EXPECT_THAT(delegate->ReadData(cb2.callback()), IsOk());
    base::RunLoop().RunUntilIdle();
  
    EXPECT_EQ(2, delegate->on_data_read_count());
    EXPECT_EQ(0, delegate->on_data_sent_count());
    EXPECT_EQ(kProtoQUIC, delegate->GetProtocol());
    EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
              delegate->GetTotalSentBytes());
    EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
                                   strlen(kResponseBody) + header.length() +
                                   spdy_trailers_frame_length),
              delegate->GetTotalReceivedBytes());
    // Check that NetLog was filled as expected.
    auto entries = net_log().GetEntries();
    size_t pos = ExpectLogContainsSomewhere(
        entries, /*min_offset=*/0,
        NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
        NetLogEventPhase::NONE);
    pos = ExpectLogContainsSomewhere(
        entries, /*min_offset=*/pos,
        NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
        NetLogEventPhase::NONE);
    ExpectLogContainsSomewhere(
        entries, /*min_offset=*/pos,
        NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
        NetLogEventPhase::NONE);
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, InterleaveReadDataAndSendData) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
  
    std::string header = ConstructDataHeader(strlen(kUploadData));
    if (!version_.UsesHttp3()) {
      AddWrite(ConstructAckAndDataPacket(++packet_number_, !kIncludeVersion, 2, 1,
                                         !kFin, kUploadData, &client_maker_));
      AddWrite(ConstructAckAndDataPacket(++packet_number_, !kIncludeVersion, 3, 3,
                                         kFin, kUploadData, &client_maker_));
    } else {
      AddWrite(ConstructAckAndDataPacket(++packet_number_, !kIncludeVersion, 2, 1,
                                         !kFin, header + std::string(kUploadData),
                                         &client_maker_));
      AddWrite(ConstructAckAndDataPacket(++packet_number_, !kIncludeVersion, 3, 3,
                                         kFin, header + std::string(kUploadData),
                                         &client_maker_));
    }
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
  
    // Client sends a data packet.
    scoped_refptr<StringIOBuffer> buf =
        base::MakeRefCounted<StringIOBuffer>(kUploadData);
  
    delegate->SendData(buf, buf->size(), false);
    delegate->WaitUntilNextCallback(kOnDataSent);
  
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    const char kResponseBody[] = "Hello world!";
  
    std::string header2 = ConstructDataHeader(strlen(kResponseBody));
    // Server sends a data packet
    int server_ack = 1;
    if (VersionUsesHttp3(version_.transport_version))
      server_ack++;
    ProcessPacket(ConstructAckAndDataPacket(3, !kIncludeVersion, server_ack++, 1,
                                            !kFin, header2 + kResponseBody,
                                            &server_maker_));
  
    EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb.WaitForResult());
    EXPECT_EQ(std::string(kResponseBody), delegate->data_received());
  
    // Client sends a data packet.
    delegate->SendData(buf, buf->size(), true);
    delegate->WaitUntilNextCallback(kOnDataSent);
  
    TestCompletionCallback cb2;
    rv = delegate->ReadData(cb2.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    ProcessPacket(
        ConstructAckAndDataPacket(4, !kIncludeVersion, server_ack++, 1, kFin,
  
                                  header2 + kResponseBody, &server_maker_));
  
    EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb2.WaitForResult());
  
    std::string expected_body(kResponseBody);
    expected_body.append(kResponseBody);
    EXPECT_EQ(expected_body, delegate->data_received());
  
    EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk());
    EXPECT_EQ(2, delegate->on_data_read_count());
    EXPECT_EQ(2, delegate->on_data_sent_count());
    EXPECT_EQ(kProtoQUIC, delegate->GetProtocol());
    EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
                                   2 * strlen(kUploadData) + 2 * header.length()),
              delegate->GetTotalSentBytes());
    EXPECT_EQ(
        static_cast<int64_t>(spdy_response_headers_frame_length +
                             2 * strlen(kResponseBody) + 2 * header2.length()),
        delegate->GetTotalReceivedBytes());
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterHeaders) {
    SetRequest("GET", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "GET";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = true;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    delegate->WaitUntilNextCallback(kOnStreamReady);
    ConfirmHandshake();
  
    // Server sends a Rst. Since the stream has sent fin, the rst is one way in
    // IETF QUIC.
    ProcessPacket(server_maker_.MakeRstPacket(
        1, !kIncludeVersion, GetNthClientInitiatedBidirectionalStreamId(0),
        quic::QUIC_STREAM_CANCELLED,
        /*include_stop_sending_if_v99=*/false));
  
    delegate->WaitUntilNextCallback(kOnFailed);
  
    TestCompletionCallback cb;
    EXPECT_THAT(delegate->ReadData(cb.callback()),
                IsError(ERR_QUIC_PROTOCOL_ERROR));
  
    base::RunLoop().RunUntilIdle();
  
    EXPECT_THAT(delegate->error(), IsError(ERR_QUIC_PROTOCOL_ERROR));
    EXPECT_EQ(0, delegate->on_data_read_count());
    EXPECT_EQ(0, delegate->on_data_sent_count());
    EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
              delegate->GetTotalSentBytes());
    EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterReadData) {
    SetRequest("GET", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    // Why does QUIC ack Rst? Is this expected?
    AddWrite(ConstructClientAckPacket(3, 1));
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "GET";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = true;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    delegate->WaitUntilNextCallback(kOnStreamReady);
    ConfirmHandshake();
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
  
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
  
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
  
    // Server sends a Rst. Since the stream has sent fin, the rst is one way in
    // IETF QUIC.
    ProcessPacket(server_maker_.MakeRstPacket(
        3, !kIncludeVersion, GetNthClientInitiatedBidirectionalStreamId(0),
        quic::QUIC_STREAM_CANCELLED,
        /*include_stop_sending_if_v99=*/false));
  
    delegate->WaitUntilNextCallback(kOnFailed);
  
    EXPECT_THAT(delegate->ReadData(cb.callback()),
                IsError(ERR_QUIC_PROTOCOL_ERROR));
    EXPECT_THAT(delegate->error(), IsError(ERR_QUIC_PROTOCOL_ERROR));
    EXPECT_EQ(0, delegate->on_data_read_count());
    EXPECT_EQ(0, delegate->on_data_sent_count());
    EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
              delegate->GetTotalSentBytes());
    EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
              delegate->GetTotalReceivedBytes());
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeReadData) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
  
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    session()->connection()->CloseConnection(
        quic::QUIC_NO_ERROR, "test", quic::ConnectionCloseBehavior::SILENT_CLOSE);
    delegate->WaitUntilNextCallback(kOnFailed);
  
    // Try to send data after OnFailed(), should not get called back.
    scoped_refptr<StringIOBuffer> buf =
        base::MakeRefCounted<StringIOBuffer>(kUploadData);
    delegate->SendData(buf, buf->size(), false);
  
    EXPECT_THAT(delegate->ReadData(cb.callback()),
                IsError(ERR_QUIC_PROTOCOL_ERROR));
    EXPECT_THAT(delegate->error(), IsError(ERR_QUIC_PROTOCOL_ERROR));
    EXPECT_EQ(0, delegate->on_data_read_count());
    EXPECT_EQ(0, delegate->on_data_sent_count());
    EXPECT_EQ(kProtoQUIC, delegate->GetProtocol());
    EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
              delegate->GetTotalSentBytes());
    EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
              delegate->GetTotalReceivedBytes());
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeStartConfirmed) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    ConfirmHandshake();
    session()->connection()->CloseConnection(
        quic::QUIC_NO_ERROR, "test", quic::ConnectionCloseBehavior::SILENT_CLOSE);
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    delegate->WaitUntilNextCallback(kOnFailed);
    EXPECT_TRUE(delegate->on_failed_called());
    EXPECT_THAT(delegate->error(), IsError(ERR_CONNECTION_CLOSED));
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeStartNotConfirmed) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    Initialize();
  
    session()->connection()->CloseConnection(
        quic::QUIC_NO_ERROR, "test", quic::ConnectionCloseBehavior::SILENT_CLOSE);
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    delegate->WaitUntilNextCallback(kOnFailed);
    EXPECT_TRUE(delegate->on_failed_called());
    EXPECT_THAT(delegate->error(), IsError(ERR_QUIC_HANDSHAKE_FAILED));
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, SessionCloseDuringOnStreamReady) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    AddWriteError(SYNCHRONOUS, ERR_CONNECTION_REFUSED);
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate(
        read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_FAILED));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnFailed);
  
    EXPECT_EQ(0, delegate->on_data_read_count());
    EXPECT_EQ(0, delegate->on_data_sent_count());
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnStreamReady) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    AddWrite(ConstructClientEarlyRstStreamPacket());
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<DeleteStreamDelegate> delegate(
        new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize,
                                 DeleteStreamDelegate::ON_STREAM_READY));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    EXPECT_EQ(0, delegate->on_data_read_count());
    EXPECT_EQ(0, delegate->on_data_sent_count());
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamAfterReadData) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    AddWrite(ConstructClientAckAndRstStreamPacket(2, 1));
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
  
    // Cancel the stream after ReadData returns ERR_IO_PENDING.
    TestCompletionCallback cb;
    EXPECT_THAT(delegate->ReadData(cb.callback()), IsError(ERR_IO_PENDING));
    delegate->DeleteStream();
  
    base::RunLoop().RunUntilIdle();
  
    EXPECT_EQ(0, delegate->on_data_read_count());
    EXPECT_EQ(0, delegate->on_data_sent_count());
    EXPECT_EQ(kProtoQUIC, delegate->GetProtocol());
    EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
              delegate->GetTotalSentBytes());
    EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
              delegate->GetTotalReceivedBytes());
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnHeadersReceived) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    AddWrite(ConstructClientAckAndRstStreamPacket(2, 1));
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<DeleteStreamDelegate> delegate(
        new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize,
                                 DeleteStreamDelegate::ON_HEADERS_RECEIVED));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
  
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
  
    base::RunLoop().RunUntilIdle();
  
    EXPECT_EQ(0, delegate->on_data_read_count());
    EXPECT_EQ(0, delegate->on_data_sent_count());
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnDataRead) {
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    AddWrite(ConstructClientAckPacket(3, 1));
    AddWrite(ConstructClientRstStreamPacket());
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate(
        read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_DATA_READ));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
  
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
  
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
  
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    const char kResponseBody[] = "Hello world!";
    std::string header = ConstructDataHeader(strlen(kResponseBody));
    // Server sends data.
    ProcessPacket(ConstructServerDataPacket(3, !kIncludeVersion, !kFin,
                                            header + kResponseBody));
    EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb.WaitForResult());
  
    base::RunLoop().RunUntilIdle();
  
    EXPECT_EQ(1, delegate->on_data_read_count());
    EXPECT_EQ(0, delegate->on_data_sent_count());
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, AsyncFinRead) {
    const char kBody[] = "here is some data";
    SetRequest("POST", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructRequestHeadersPacketInner(
        GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY,
        &spdy_request_headers_frame_length));
    std::string header = ConstructDataHeader(strlen(kBody));
    if (version_.UsesHttp3()) {
      AddWrite(ConstructClientDataPacket(kIncludeVersion, kFin, header + kBody));
    } else {
      AddWrite(ConstructClientDataPacket(kIncludeVersion, kFin, kBody));
    }
    AddWrite(ConstructClientAckPacket(3, 1));
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "POST";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = false;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
  
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Send a Data packet with fin set.
    scoped_refptr<StringIOBuffer> buf1 =
        base::MakeRefCounted<StringIOBuffer>(kBody);
    delegate->SendData(buf1, buf1->size(), /*fin*/ true);
    delegate->WaitUntilNextCallback(kOnDataSent);
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
  
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
  
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
  
    // Read the body, which will complete asynchronously.
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    const char kResponseBody[] = "Hello world!";
    std::string header2 = ConstructDataHeader(strlen(kResponseBody));
  
    // Server sends data with the fin set, which should result in the stream
    // being closed and hence no RST_STREAM will be sent.
    ProcessPacket(ConstructServerDataPacket(3, !kIncludeVersion, kFin,
                                            header2 + kResponseBody));
    EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb.WaitForResult());
  
    base::RunLoop().RunUntilIdle();
  
    EXPECT_EQ(1, delegate->on_data_read_count());
    EXPECT_EQ(1, delegate->on_data_sent_count());
  }
  
  TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnTrailersReceived) {
    SetRequest("GET", "/", DEFAULT_PRIORITY);
    size_t spdy_request_headers_frame_length;
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
    if (VersionUsesHttp3(version_.transport_version))
      AddWrite(ConstructInitialSettingsPacket());
    client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
    AddWrite(ConstructRequestHeadersPacket(kFin, DEFAULT_PRIORITY,
                                           &spdy_request_headers_frame_length));
    AddWrite(ConstructClientAckPacket(3, 1));  // Ack the data packet
    AddWrite(ConstructClientAckAndRstStreamPacket(4, 4));
  
    Initialize();
  
    BidirectionalStreamRequestInfo request;
    request.method = "GET";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = true;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<DeleteStreamDelegate> delegate(
        new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize,
                                 DeleteStreamDelegate::ON_TRAILERS_RECEIVED));
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    ConfirmHandshake();
    delegate->WaitUntilNextCallback(kOnStreamReady);
  
    // Server acks the request.
    ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1));
  
    // Server sends the response headers.
    spdy::Http2HeaderBlock response_headers = ConstructResponseHeaders("200");
  
    size_t spdy_response_headers_frame_length;
    ProcessPacket(
        ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
                                       &spdy_response_headers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnHeadersReceived);
  
    EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
  
    TestCompletionCallback cb;
    int rv = delegate->ReadData(cb.callback());
    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
    const char kResponseBody[] = "Hello world!";
  
    // Server sends data.
    std::string header = ConstructDataHeader(strlen(kResponseBody));
    ProcessPacket(ConstructServerDataPacket(3, !kIncludeVersion, !kFin,
                                            header + kResponseBody));
  
    EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb.WaitForResult());
    EXPECT_EQ(std::string(kResponseBody), delegate->data_received());
  
    size_t spdy_trailers_frame_length;
    spdy::Http2HeaderBlock trailers;
    trailers["foo"] = "bar";
    if (!quic::VersionUsesHttp3(version_.transport_version)) {
      trailers[quic::kFinalOffsetHeaderKey] =
          base::NumberToString(strlen(kResponseBody));
    }
    // Server sends trailers.
    ProcessPacket(ConstructResponseTrailersPacket(4, kFin, trailers.Clone(),
                                                  &spdy_trailers_frame_length));
  
    delegate->WaitUntilNextCallback(kOnTrailersReceived);
    trailers.erase(quic::kFinalOffsetHeaderKey);
    EXPECT_EQ(trailers, delegate->trailers());
  
    base::RunLoop().RunUntilIdle();
  
    EXPECT_EQ(1, delegate->on_data_read_count());
    EXPECT_EQ(0, delegate->on_data_sent_count());
  }
  
  // Tests that if QuicChromiumClientSession is closed after
  // BidirectionalStreamQuicImpl::OnStreamReady() but before
  // QuicChromiumClientSession::Handle::ReleaseStream() is called, there is no
  // crash. Regression test for crbug.com/754823.
  TEST_P(BidirectionalStreamQuicImplTest, ReleaseStreamFails) {
    SetRequest("GET", "/", DEFAULT_PRIORITY);
    Initialize();
  
    ConfirmHandshake();
  
    BidirectionalStreamRequestInfo request;
    request.method = "GET";
    request.url = GURL("http://www.google.com/");
    request.end_stream_on_headers = true;
    request.priority = DEFAULT_PRIORITY;
  
    scoped_refptr<IOBuffer> read_buffer =
        base::MakeRefCounted<IOBuffer>(kReadBufferSize);
    std::unique_ptr<TestDelegateBase> delegate(
        new TestDelegateBase(read_buffer.get(), kReadBufferSize));
    delegate->set_trailers_expected(true);
    // QuicChromiumClientSession::Handle::RequestStream() returns OK synchronously
    // because Initialize() has established a Session.
    delegate->Start(&request, net_log().bound(),
                    session()->CreateHandle(destination_));
    // Now closes the underlying session.
    session_->CloseSessionOnError(ERR_ABORTED, quic::QUIC_INTERNAL_ERROR,
                                  quic::ConnectionCloseBehavior::SILENT_CLOSE);
    delegate->WaitUntilNextCallback(kOnFailed);
  
    EXPECT_THAT(delegate->error(), IsError(ERR_CONNECTION_CLOSED));
  }
  
  }  // namespace test
  
  }  // namespace net
  