Project import generated by Copybara.

PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/quic_crypto_stream.cc b/quic/core/quic_crypto_stream.cc
new file mode 100644
index 0000000..aef431d
--- /dev/null
+++ b/quic/core/quic_crypto_stream.cc
@@ -0,0 +1,418 @@
+// Copyright (c) 2012 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/third_party/quiche/src/quic/core/quic_crypto_stream.h"
+
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+#define ENDPOINT                                                   \
+  (session()->perspective() == Perspective::IS_SERVER ? "Server: " \
+                                                      : "Client:"  \
+                                                        " ")
+
+QuicCryptoStream::QuicCryptoStream(QuicSession* session)
+    : QuicStream(QuicUtils::GetCryptoStreamId(
+                     session->connection()->transport_version()),
+                 session,
+                 /*is_static=*/true,
+                 BIDIRECTIONAL),
+      substreams_{{this, ENCRYPTION_NONE},
+                  {this, ENCRYPTION_ZERO_RTT},
+                  {this, ENCRYPTION_FORWARD_SECURE}} {
+  // The crypto stream is exempt from connection level flow control.
+  DisableConnectionFlowControlForThisStream();
+}
+
+QuicCryptoStream::~QuicCryptoStream() {}
+
+// static
+QuicByteCount QuicCryptoStream::CryptoMessageFramingOverhead(
+    QuicTransportVersion version,
+    QuicConnectionId connection_id) {
+  DCHECK(QuicUtils::IsConnectionIdValidForVersion(connection_id, version));
+  return QuicPacketCreator::StreamFramePacketOverhead(
+      version, static_cast<QuicConnectionIdLength>(connection_id.length()),
+      PACKET_0BYTE_CONNECTION_ID,
+      /*include_version=*/true,
+      /*include_diversification_nonce=*/true,
+      version > QUIC_VERSION_43 ? PACKET_4BYTE_PACKET_NUMBER
+                                : PACKET_1BYTE_PACKET_NUMBER,
+      VARIABLE_LENGTH_INTEGER_LENGTH_1, VARIABLE_LENGTH_INTEGER_LENGTH_2,
+      /*offset=*/0);
+}
+
+void QuicCryptoStream::OnCryptoFrame(const QuicCryptoFrame& frame) {
+  QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47)
+      << "Versions less than 47 shouldn't receive CRYPTO frames";
+  EncryptionLevel level = session()->connection()->last_decrypted_level();
+  substreams_[level].sequencer.OnCryptoFrame(frame);
+}
+
+void QuicCryptoStream::OnStreamFrame(const QuicStreamFrame& frame) {
+  if (session()->connection()->transport_version() >= QUIC_VERSION_47) {
+    QUIC_PEER_BUG
+        << "Crypto data received in stream frame instead of crypto frame";
+    CloseConnectionWithDetails(QUIC_INVALID_STREAM_DATA,
+                               "Unexpected stream frame");
+  }
+  QuicStream::OnStreamFrame(frame);
+}
+
+void QuicCryptoStream::OnDataAvailable() {
+  EncryptionLevel level = session()->connection()->last_decrypted_level();
+  if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+    // Versions less than 47 only support QUIC crypto, which ignores the
+    // EncryptionLevel passed into CryptoMessageParser::ProcessInput (and
+    // OnDataAvailableInSequencer).
+    OnDataAvailableInSequencer(sequencer(), level);
+    return;
+  }
+  OnDataAvailableInSequencer(&substreams_[level].sequencer, level);
+}
+
+void QuicCryptoStream::OnDataAvailableInSequencer(
+    QuicStreamSequencer* sequencer,
+    EncryptionLevel level) {
+  struct iovec iov;
+  while (sequencer->GetReadableRegion(&iov)) {
+    QuicStringPiece data(static_cast<char*>(iov.iov_base), iov.iov_len);
+    if (!crypto_message_parser()->ProcessInput(data, level)) {
+      CloseConnectionWithDetails(crypto_message_parser()->error(),
+                                 crypto_message_parser()->error_detail());
+      return;
+    }
+    sequencer->MarkConsumed(iov.iov_len);
+    if (handshake_confirmed() &&
+        crypto_message_parser()->InputBytesRemaining() == 0) {
+      // If the handshake is complete and the current message has been fully
+      // processed then no more handshake messages are likely to arrive soon
+      // so release the memory in the stream sequencer.
+      sequencer->ReleaseBufferIfEmpty();
+    }
+  }
+}
+
+bool QuicCryptoStream::ExportKeyingMaterial(QuicStringPiece label,
+                                            QuicStringPiece context,
+                                            size_t result_len,
+                                            QuicString* result) const {
+  if (!handshake_confirmed()) {
+    QUIC_DLOG(ERROR) << "ExportKeyingMaterial was called before forward-secure"
+                     << "encryption was established.";
+    return false;
+  }
+  return CryptoUtils::ExportKeyingMaterial(
+      crypto_negotiated_params().subkey_secret, label, context, result_len,
+      result);
+}
+
+void QuicCryptoStream::WriteCryptoData(EncryptionLevel level,
+                                       QuicStringPiece data) {
+  if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+    // The QUIC crypto handshake takes care of setting the appropriate
+    // encryption level before writing data. Since that is the only handshake
+    // supported in versions less than 47, |level| can be ignored here.
+    WriteOrBufferData(data, /* fin */ false, /* ack_listener */ nullptr);
+    return;
+  }
+  if (data.empty()) {
+    QUIC_BUG << "Empty crypto data being written";
+    return;
+  }
+  // Append |data| to the send buffer for this encryption level.
+  struct iovec iov(QuicUtils::MakeIovec(data));
+  QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
+  QuicStreamOffset offset = send_buffer->stream_offset();
+  send_buffer->SaveStreamData(&iov, /*iov_count=*/1, /*iov_offset=*/0,
+                              data.length());
+  if (kMaxStreamLength - offset < data.length()) {
+    QUIC_BUG << "Writing too much crypto handshake data";
+    // TODO(nharper): Switch this to an IETF QUIC error code, possibly
+    // INTERNAL_ERROR?
+    CloseConnectionWithDetails(QUIC_STREAM_LENGTH_OVERFLOW,
+                               "Writing too much crypto handshake data");
+  }
+
+  EncryptionLevel current_level = session()->connection()->encryption_level();
+  session()->connection()->SetDefaultEncryptionLevel(level);
+  size_t bytes_consumed =
+      session()->connection()->SendCryptoData(level, data.length(), offset);
+  session()->connection()->SetDefaultEncryptionLevel(current_level);
+
+  send_buffer->OnStreamDataConsumed(bytes_consumed);
+}
+
+void QuicCryptoStream::OnSuccessfulVersionNegotiation(
+    const ParsedQuicVersion& version) {}
+
+bool QuicCryptoStream::OnCryptoFrameAcked(const QuicCryptoFrame& frame,
+                                          QuicTime::Delta ack_delay_time) {
+  QuicByteCount newly_acked_length = 0;
+  if (!substreams_[frame.level].send_buffer.OnStreamDataAcked(
+          frame.offset, frame.data_length, &newly_acked_length)) {
+    CloseConnectionWithDetails(QUIC_INTERNAL_ERROR,
+                               "Trying to ack unsent crypto data.");
+    return false;
+  }
+  return newly_acked_length > 0;
+}
+
+void QuicCryptoStream::NeuterUnencryptedStreamData() {
+  if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+    for (const auto& interval : bytes_consumed_[ENCRYPTION_NONE]) {
+      QuicByteCount newly_acked_length = 0;
+      send_buffer().OnStreamDataAcked(
+          interval.min(), interval.max() - interval.min(), &newly_acked_length);
+    }
+    return;
+  }
+  QuicStreamSendBuffer* send_buffer = &substreams_[ENCRYPTION_NONE].send_buffer;
+  // TODO(nharper): Consider adding a Clear() method to QuicStreamSendBuffer to
+  // replace the following code.
+  QuicIntervalSet<QuicStreamOffset> to_ack = send_buffer->bytes_acked();
+  to_ack.Complement(0, send_buffer->stream_offset());
+  for (const auto& interval : to_ack) {
+    QuicByteCount newly_acked_length = 0;
+    send_buffer->OnStreamDataAcked(
+        interval.min(), interval.max() - interval.min(), &newly_acked_length);
+  }
+}
+
+void QuicCryptoStream::OnStreamDataConsumed(size_t bytes_consumed) {
+  if (session()->connection()->transport_version() >= QUIC_VERSION_47) {
+    QUIC_BUG << "Stream data consumed when CRYPTO frames should be in use";
+  }
+  if (bytes_consumed > 0) {
+    bytes_consumed_[session()->connection()->encryption_level()].Add(
+        stream_bytes_written(), stream_bytes_written() + bytes_consumed);
+  }
+  QuicStream::OnStreamDataConsumed(bytes_consumed);
+}
+
+bool QuicCryptoStream::HasPendingCryptoRetransmission() {
+  if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+    return false;
+  }
+  for (EncryptionLevel level :
+       {ENCRYPTION_NONE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+    if (substreams_[level].send_buffer.HasPendingRetransmission()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void QuicCryptoStream::WritePendingCryptoRetransmission() {
+  QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47)
+      << "Versions less than 47 don't write CRYPTO frames";
+  EncryptionLevel current_encryption_level =
+      session()->connection()->encryption_level();
+  for (EncryptionLevel level :
+       {ENCRYPTION_NONE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+    QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
+    session()->connection()->SetDefaultEncryptionLevel(level);
+    while (send_buffer->HasPendingRetransmission()) {
+      auto pending = send_buffer->NextPendingRetransmission();
+      size_t bytes_consumed = session()->connection()->SendCryptoData(
+          level, pending.length, pending.offset);
+      send_buffer->OnStreamDataRetransmitted(pending.offset, bytes_consumed);
+    }
+  }
+  session()->connection()->SetDefaultEncryptionLevel(current_encryption_level);
+}
+
+void QuicCryptoStream::WritePendingRetransmission() {
+  while (HasPendingRetransmission()) {
+    StreamPendingRetransmission pending =
+        send_buffer().NextPendingRetransmission();
+    QuicIntervalSet<QuicStreamOffset> retransmission(
+        pending.offset, pending.offset + pending.length);
+    EncryptionLevel retransmission_encryption_level = ENCRYPTION_NONE;
+    // Determine the encryption level to write the retransmission
+    // at. The retransmission should be written at the same encryption level
+    // as the original transmission.
+    for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
+      if (retransmission.Intersects(bytes_consumed_[i])) {
+        retransmission_encryption_level = static_cast<EncryptionLevel>(i);
+        retransmission.Intersection(bytes_consumed_[i]);
+        break;
+      }
+    }
+    pending.offset = retransmission.begin()->min();
+    pending.length =
+        retransmission.begin()->max() - retransmission.begin()->min();
+    EncryptionLevel current_encryption_level =
+        session()->connection()->encryption_level();
+    // Set appropriate encryption level.
+    session()->connection()->SetDefaultEncryptionLevel(
+        retransmission_encryption_level);
+    QuicConsumedData consumed = session()->WritevData(
+        this, id(), pending.length, pending.offset, NO_FIN);
+    QUIC_DVLOG(1) << ENDPOINT << "stream " << id()
+                  << " tries to retransmit stream data [" << pending.offset
+                  << ", " << pending.offset + pending.length
+                  << ") with encryption level: "
+                  << retransmission_encryption_level
+                  << ", consumed: " << consumed;
+    OnStreamFrameRetransmitted(pending.offset, consumed.bytes_consumed,
+                               consumed.fin_consumed);
+    // Restore encryption level.
+    session()->connection()->SetDefaultEncryptionLevel(
+        current_encryption_level);
+    if (consumed.bytes_consumed < pending.length) {
+      // The connection is write blocked.
+      break;
+    }
+  }
+}
+
+bool QuicCryptoStream::RetransmitStreamData(QuicStreamOffset offset,
+                                            QuicByteCount data_length,
+                                            bool /*fin*/) {
+  QuicIntervalSet<QuicStreamOffset> retransmission(offset,
+                                                   offset + data_length);
+  // Determine the encryption level to send data. This only needs to be once as
+  // [offset, offset + data_length) is guaranteed to be in the same packet.
+  EncryptionLevel send_encryption_level = ENCRYPTION_NONE;
+  for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
+    if (retransmission.Intersects(bytes_consumed_[i])) {
+      send_encryption_level = static_cast<EncryptionLevel>(i);
+      break;
+    }
+  }
+  retransmission.Difference(bytes_acked());
+  EncryptionLevel current_encryption_level =
+      session()->connection()->encryption_level();
+  for (const auto& interval : retransmission) {
+    QuicStreamOffset retransmission_offset = interval.min();
+    QuicByteCount retransmission_length = interval.max() - interval.min();
+    // Set appropriate encryption level.
+    session()->connection()->SetDefaultEncryptionLevel(send_encryption_level);
+    QuicConsumedData consumed = session()->WritevData(
+        this, id(), retransmission_length, retransmission_offset, NO_FIN);
+    QUIC_DVLOG(1) << ENDPOINT << "stream " << id()
+                  << " is forced to retransmit stream data ["
+                  << retransmission_offset << ", "
+                  << retransmission_offset + retransmission_length
+                  << "), with encryption level: " << send_encryption_level
+                  << ", consumed: " << consumed;
+    OnStreamFrameRetransmitted(retransmission_offset, consumed.bytes_consumed,
+                               consumed.fin_consumed);
+    // Restore encryption level.
+    session()->connection()->SetDefaultEncryptionLevel(
+        current_encryption_level);
+    if (consumed.bytes_consumed < retransmission_length) {
+      // The connection is write blocked.
+      return false;
+    }
+  }
+
+  return true;
+}
+
+uint64_t QuicCryptoStream::crypto_bytes_read() const {
+  if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+    return stream_bytes_read();
+  }
+  return substreams_[ENCRYPTION_NONE].sequencer.NumBytesConsumed() +
+         substreams_[ENCRYPTION_ZERO_RTT].sequencer.NumBytesConsumed() +
+         substreams_[ENCRYPTION_FORWARD_SECURE].sequencer.NumBytesConsumed();
+}
+
+uint64_t QuicCryptoStream::BytesReadOnLevel(EncryptionLevel level) const {
+  return substreams_[level].sequencer.NumBytesConsumed();
+}
+
+bool QuicCryptoStream::WriteCryptoFrame(EncryptionLevel level,
+                                        QuicStreamOffset offset,
+                                        QuicByteCount data_length,
+                                        QuicDataWriter* writer) {
+  QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47)
+      << "Versions less than 47 don't write CRYPTO frames (2)";
+  return substreams_[level].send_buffer.WriteStreamData(offset, data_length,
+                                                        writer);
+}
+
+void QuicCryptoStream::OnCryptoFrameLost(QuicCryptoFrame* crypto_frame) {
+  QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47)
+      << "Versions less than 47 don't lose CRYPTO frames";
+  substreams_[crypto_frame->level].send_buffer.OnStreamDataLost(
+      crypto_frame->offset, crypto_frame->data_length);
+}
+
+void QuicCryptoStream::RetransmitData(QuicCryptoFrame* crypto_frame) {
+  QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47)
+      << "Versions less than 47 don't retransmit CRYPTO frames";
+  QuicIntervalSet<QuicStreamOffset> retransmission(
+      crypto_frame->offset, crypto_frame->offset + crypto_frame->data_length);
+  QuicStreamSendBuffer* send_buffer =
+      &substreams_[crypto_frame->level].send_buffer;
+  retransmission.Difference(send_buffer->bytes_acked());
+  if (retransmission.Empty()) {
+    return;
+  }
+  EncryptionLevel current_encryption_level =
+      session()->connection()->encryption_level();
+  for (const auto& interval : retransmission) {
+    size_t retransmission_offset = interval.min();
+    size_t retransmission_length = interval.max() - interval.min();
+    session()->connection()->SetDefaultEncryptionLevel(crypto_frame->level);
+    size_t bytes_consumed = session()->connection()->SendCryptoData(
+        crypto_frame->level, retransmission_length, retransmission_offset);
+    send_buffer->OnStreamDataRetransmitted(retransmission_offset,
+                                           bytes_consumed);
+  }
+  session()->connection()->SetDefaultEncryptionLevel(current_encryption_level);
+}
+
+bool QuicCryptoStream::IsFrameOutstanding(EncryptionLevel level,
+                                          size_t offset,
+                                          size_t length) const {
+  if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+    // This only happens if a client was originally configured for a version
+    // greater than 45, but received a version negotiation packet and is
+    // attempting to retransmit for a version less than 47. Outside of tests,
+    // this is a misconfiguration of the client, and this connection will be
+    // doomed. Return false here to avoid trying to retransmit CRYPTO frames on
+    // the wrong transport version.
+    return false;
+  }
+  return substreams_[level].send_buffer.IsStreamDataOutstanding(offset, length);
+}
+
+bool QuicCryptoStream::IsWaitingForAcks() const {
+  if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+    return QuicStream::IsWaitingForAcks();
+  }
+  for (EncryptionLevel level :
+       {ENCRYPTION_NONE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+    if (substreams_[level].send_buffer.stream_bytes_outstanding()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+QuicCryptoStream::CryptoSubstream::CryptoSubstream(
+    QuicCryptoStream* crypto_stream,
+    EncryptionLevel)
+    : sequencer(crypto_stream),
+      send_buffer(crypto_stream->session()
+                      ->connection()
+                      ->helper()
+                      ->GetStreamSendBufferAllocator()) {}
+
+#undef ENDPOINT  // undef for jumbo builds
+}  // namespace quic