Project import generated by Copybara.

PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/chlo_extractor.cc b/quic/core/chlo_extractor.cc
new file mode 100644
index 0000000..15a118b
--- /dev/null
+++ b/quic/core/chlo_extractor.cc
@@ -0,0 +1,309 @@
+// Copyright (c) 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/third_party/quiche/src/quic/core/chlo_extractor.h"
+
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.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/quic_framer.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+
+namespace quic {
+
+namespace {
+
+class ChloFramerVisitor : public QuicFramerVisitorInterface,
+                          public CryptoFramerVisitorInterface {
+ public:
+  ChloFramerVisitor(QuicFramer* framer,
+                    const QuicTagVector& create_session_tag_indicators,
+                    ChloExtractor::Delegate* delegate);
+
+  ~ChloFramerVisitor() override = default;
+
+  // QuicFramerVisitorInterface implementation
+  void OnError(QuicFramer* framer) override {}
+  bool OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                 PacketHeaderFormat form) override;
+  void OnPacket() override {}
+  void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {}
+  void OnVersionNegotiationPacket(
+      const QuicVersionNegotiationPacket& packet) override {}
+  bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override;
+  bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
+  void OnDecryptedPacket(EncryptionLevel level) override {}
+  bool OnPacketHeader(const QuicPacketHeader& header) override;
+  void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
+  bool OnStreamFrame(const QuicStreamFrame& frame) override;
+  bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
+  bool OnAckFrameStart(QuicPacketNumber largest_acked,
+                       QuicTime::Delta ack_delay_time) override;
+  bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override;
+  bool OnAckTimestamp(QuicPacketNumber packet_number,
+                      QuicTime timestamp) override;
+  bool OnAckFrameEnd(QuicPacketNumber start) override;
+  bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override;
+  bool OnPingFrame(const QuicPingFrame& frame) override;
+  bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override;
+  bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override;
+  bool OnApplicationCloseFrame(const QuicApplicationCloseFrame& frame) override;
+  bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override;
+  bool OnRetireConnectionIdFrame(
+      const QuicRetireConnectionIdFrame& frame) override;
+  bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override;
+  bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override;
+  bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override;
+  bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override;
+  bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
+  bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override;
+  bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override;
+  bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
+  bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
+  bool OnPaddingFrame(const QuicPaddingFrame& frame) override;
+  bool OnMessageFrame(const QuicMessageFrame& frame) override;
+  void OnPacketComplete() override {}
+  bool IsValidStatelessResetToken(QuicUint128 token) const override;
+  void OnAuthenticatedIetfStatelessResetPacket(
+      const QuicIetfStatelessResetPacket& packet) override {}
+
+  // CryptoFramerVisitorInterface implementation.
+  void OnError(CryptoFramer* framer) override;
+  void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
+
+  // Shared implementation between OnStreamFrame and OnCryptoFrame.
+  bool OnHandshakeData(QuicStringPiece data);
+
+  bool found_chlo() { return found_chlo_; }
+  bool chlo_contains_tags() { return chlo_contains_tags_; }
+
+ private:
+  QuicFramer* framer_;
+  const QuicTagVector& create_session_tag_indicators_;
+  ChloExtractor::Delegate* delegate_;
+  bool found_chlo_;
+  bool chlo_contains_tags_;
+  QuicConnectionId connection_id_;
+};
+
+ChloFramerVisitor::ChloFramerVisitor(
+    QuicFramer* framer,
+    const QuicTagVector& create_session_tag_indicators,
+    ChloExtractor::Delegate* delegate)
+    : framer_(framer),
+      create_session_tag_indicators_(create_session_tag_indicators),
+      delegate_(delegate),
+      found_chlo_(false),
+      chlo_contains_tags_(false),
+      connection_id_(EmptyQuicConnectionId()) {}
+
+bool ChloFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                                  PacketHeaderFormat /*form*/) {
+  if (!framer_->IsSupportedVersion(version)) {
+    return false;
+  }
+  framer_->set_version(version);
+  return true;
+}
+
+bool ChloFramerVisitor::OnUnauthenticatedPublicHeader(
+    const QuicPacketHeader& header) {
+  connection_id_ = header.destination_connection_id;
+  return true;
+}
+bool ChloFramerVisitor::OnUnauthenticatedHeader(
+    const QuicPacketHeader& header) {
+  return true;
+}
+bool ChloFramerVisitor::OnPacketHeader(const QuicPacketHeader& header) {
+  return true;
+}
+void ChloFramerVisitor::OnCoalescedPacket(const QuicEncryptedPacket& packet) {}
+bool ChloFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) {
+  if (framer_->transport_version() >= QUIC_VERSION_47) {
+    // CHLO will be sent in CRYPTO frames in v47 and above.
+    return false;
+  }
+  QuicStringPiece data(frame.data_buffer, frame.data_length);
+  if (frame.stream_id ==
+          QuicUtils::GetCryptoStreamId(framer_->transport_version()) &&
+      frame.offset == 0 && QuicTextUtils::StartsWith(data, "CHLO")) {
+    return OnHandshakeData(data);
+  }
+  return true;
+}
+
+bool ChloFramerVisitor::OnCryptoFrame(const QuicCryptoFrame& frame) {
+  if (framer_->transport_version() < QUIC_VERSION_47) {
+    // CHLO will be in stream frames before v47.
+    return false;
+  }
+  QuicStringPiece data(frame.data_buffer, frame.data_length);
+  if (frame.offset == 0 && QuicTextUtils::StartsWith(data, "CHLO")) {
+    return OnHandshakeData(data);
+  }
+  return true;
+}
+
+bool ChloFramerVisitor::OnHandshakeData(QuicStringPiece data) {
+  CryptoFramer crypto_framer;
+  crypto_framer.set_visitor(this);
+  if (!crypto_framer.ProcessInput(data)) {
+    return false;
+  }
+  // Interrogate the crypto framer and see if there are any
+  // intersecting tags between what we saw in the maybe-CHLO and the
+  // indicator set.
+  for (const QuicTag tag : create_session_tag_indicators_) {
+    if (crypto_framer.HasTag(tag)) {
+      chlo_contains_tags_ = true;
+    }
+  }
+  if (chlo_contains_tags_ && delegate_) {
+    // Unfortunately, because this is a partial CHLO,
+    // OnHandshakeMessage was never called, so the ALPN was never
+    // extracted. Fake it up a bit and send it to the delegate so that
+    // the correct dispatch can happen.
+    crypto_framer.ForceHandshake();
+  }
+
+  return true;
+}
+
+bool ChloFramerVisitor::OnAckFrameStart(QuicPacketNumber /*largest_acked*/,
+                                        QuicTime::Delta /*ack_delay_time*/) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnAckRange(QuicPacketNumber /*start*/,
+                                   QuicPacketNumber /*end*/) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnAckTimestamp(QuicPacketNumber /*packet_number*/,
+                                       QuicTime /*timestamp*/) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnAckFrameEnd(QuicPacketNumber /*start*/) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnStopWaitingFrame(const QuicStopWaitingFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnPingFrame(const QuicPingFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnConnectionCloseFrame(
+    const QuicConnectionCloseFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnApplicationCloseFrame(
+    const QuicApplicationCloseFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnPathChallengeFrame(
+    const QuicPathChallengeFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnPathResponseFrame(
+    const QuicPathResponseFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnWindowUpdateFrame(
+    const QuicWindowUpdateFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnBlockedFrame(const QuicBlockedFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnNewConnectionIdFrame(
+    const QuicNewConnectionIdFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnRetireConnectionIdFrame(
+    const QuicRetireConnectionIdFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnNewTokenFrame(const QuicNewTokenFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnPaddingFrame(const QuicPaddingFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnMessageFrame(const QuicMessageFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::IsValidStatelessResetToken(QuicUint128 token) const {
+  return false;
+}
+
+bool ChloFramerVisitor::OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) {
+  return true;
+}
+
+bool ChloFramerVisitor::OnStreamIdBlockedFrame(
+    const QuicStreamIdBlockedFrame& frame) {
+  return true;
+}
+
+void ChloFramerVisitor::OnError(CryptoFramer* framer) {}
+
+void ChloFramerVisitor::OnHandshakeMessage(
+    const CryptoHandshakeMessage& message) {
+  if (delegate_ != nullptr) {
+    delegate_->OnChlo(framer_->transport_version(), connection_id_, message);
+  }
+  found_chlo_ = true;
+}
+
+}  // namespace
+
+// static
+bool ChloExtractor::Extract(const QuicEncryptedPacket& packet,
+                            const ParsedQuicVersionVector& versions,
+                            const QuicTagVector& create_session_tag_indicators,
+                            Delegate* delegate,
+                            uint8_t connection_id_length) {
+  QuicFramer framer(versions, QuicTime::Zero(), Perspective::IS_SERVER,
+                    connection_id_length);
+  ChloFramerVisitor visitor(&framer, create_session_tag_indicators, delegate);
+  framer.set_visitor(&visitor);
+  if (!framer.ProcessPacket(packet)) {
+    return false;
+  }
+  return visitor.found_chlo() || visitor.chlo_contains_tags();
+}
+
+}  // namespace quic