Project import generated by Copybara.

PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/frames/quic_ack_frame.cc b/quic/core/frames/quic_ack_frame.cc
new file mode 100644
index 0000000..389f1c0
--- /dev/null
+++ b/quic/core/frames/quic_ack_frame.cc
@@ -0,0 +1,326 @@
+// 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/frames/quic_ack_frame.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
+
+namespace quic {
+
+namespace {
+
+const QuicPacketCount kMaxPrintRange = 128;
+
+uint64_t PacketNumberIntervalLength(
+    const QuicInterval<QuicPacketNumber>& interval) {
+  if (interval.Empty()) {
+    return 0u;
+  }
+  return interval.max() - interval.min();
+}
+}  // namespace
+
+bool IsAwaitingPacket(const QuicAckFrame& ack_frame,
+                      QuicPacketNumber packet_number,
+                      QuicPacketNumber peer_least_packet_awaiting_ack) {
+  DCHECK(packet_number.IsInitialized());
+  return (!peer_least_packet_awaiting_ack.IsInitialized() ||
+          packet_number >= peer_least_packet_awaiting_ack) &&
+         !ack_frame.packets.Contains(packet_number);
+}
+
+QuicAckFrame::QuicAckFrame()
+    : ack_delay_time(QuicTime::Delta::Infinite()),
+      ecn_counters_populated(false),
+      ect_0_count(0),
+      ect_1_count(0),
+      ecn_ce_count(0) {}
+
+QuicAckFrame::QuicAckFrame(const QuicAckFrame& other) = default;
+
+QuicAckFrame::~QuicAckFrame() {}
+
+std::ostream& operator<<(std::ostream& os, const QuicAckFrame& ack_frame) {
+  os << "{ largest_acked: " << LargestAcked(ack_frame)
+     << ", ack_delay_time: " << ack_frame.ack_delay_time.ToMicroseconds()
+     << ", packets: [ " << ack_frame.packets << " ]"
+     << ", received_packets: [ ";
+  for (const std::pair<QuicPacketNumber, QuicTime>& p :
+       ack_frame.received_packet_times) {
+    os << p.first << " at " << p.second.ToDebuggingValue() << " ";
+  }
+  os << " ]";
+  os << ", ecn_counters_populated: " << ack_frame.ecn_counters_populated;
+  if (ack_frame.ecn_counters_populated) {
+    os << ", ect_0_count: " << ack_frame.ect_0_count
+       << ", ect_1_count: " << ack_frame.ect_1_count
+       << ", ecn_ce_count: " << ack_frame.ecn_ce_count;
+  }
+
+  os << " }\n";
+  return os;
+}
+
+void QuicAckFrame::Clear() {
+  largest_acked.Clear();
+  ack_delay_time = QuicTime::Delta::Infinite();
+  received_packet_times.clear();
+  packets.Clear();
+}
+
+PacketNumberQueue::PacketNumberQueue() {}
+PacketNumberQueue::PacketNumberQueue(const PacketNumberQueue& other) = default;
+PacketNumberQueue::PacketNumberQueue(PacketNumberQueue&& other) = default;
+PacketNumberQueue::~PacketNumberQueue() {}
+
+PacketNumberQueue& PacketNumberQueue::operator=(
+    const PacketNumberQueue& other) = default;
+PacketNumberQueue& PacketNumberQueue::operator=(PacketNumberQueue&& other) =
+    default;
+
+void PacketNumberQueue::Add(QuicPacketNumber packet_number) {
+  if (!packet_number.IsInitialized()) {
+    return;
+  }
+  // Check if the deque is empty
+  if (packet_number_deque_.empty()) {
+    packet_number_deque_.push_front(
+        QuicInterval<QuicPacketNumber>(packet_number, packet_number + 1));
+    return;
+  }
+  QuicInterval<QuicPacketNumber> back = packet_number_deque_.back();
+
+  // Check for the typical case,
+  // when the next packet in order is acked
+  if (back.max() == packet_number) {
+    packet_number_deque_.back().SetMax(packet_number + 1);
+    return;
+  }
+  // Check if the next packet in order is skipped
+  if (back.max() < packet_number) {
+    packet_number_deque_.push_back(
+        QuicInterval<QuicPacketNumber>(packet_number, packet_number + 1));
+    return;
+  }
+
+  QuicInterval<QuicPacketNumber> front = packet_number_deque_.front();
+  // Check if the packet can be  popped on the front
+  if (front.min() > packet_number + 1) {
+    packet_number_deque_.push_front(
+        QuicInterval<QuicPacketNumber>(packet_number, packet_number + 1));
+    return;
+  }
+  if (front.min() == packet_number + 1) {
+    packet_number_deque_.front().SetMin(packet_number);
+    return;
+  }
+
+  int i = packet_number_deque_.size() - 1;
+  // Iterating through the queue backwards
+  // to find a proper place for the packet
+  while (i >= 0) {
+    QuicInterval<QuicPacketNumber> packet_interval = packet_number_deque_[i];
+    DCHECK(packet_interval.min() < packet_interval.max());
+    // Check if the packet is contained in an interval already
+    if (packet_interval.Contains(packet_number)) {
+      return;
+    }
+
+    // Check if the packet can extend an interval.
+    if (packet_interval.max() == packet_number) {
+      packet_number_deque_[i].SetMax(packet_number + 1);
+      return;
+    }
+    // Check if the packet can extend an interval
+    // and merge two intervals if needed.
+    // There is no need to merge an interval in the previous
+    // if statement, as all merges will happen here.
+    if (packet_interval.min() == packet_number + 1) {
+      packet_number_deque_[i].SetMin(packet_number);
+      if (i > 0 && packet_number == packet_number_deque_[i - 1].max()) {
+        packet_number_deque_[i - 1].SetMax(packet_interval.max());
+        packet_number_deque_.erase(packet_number_deque_.begin() + i);
+      }
+      return;
+    }
+
+    // Check if we need to make a new interval for the packet
+    if (packet_interval.max() < packet_number + 1) {
+      packet_number_deque_.insert(
+          packet_number_deque_.begin() + i + 1,
+          QuicInterval<QuicPacketNumber>(packet_number, packet_number + 1));
+      return;
+    }
+    i--;
+  }
+}
+
+void PacketNumberQueue::AddRange(QuicPacketNumber lower,
+                                 QuicPacketNumber higher) {
+  if (!lower.IsInitialized() || !higher.IsInitialized() || lower >= higher) {
+    return;
+  }
+  if (packet_number_deque_.empty()) {
+    packet_number_deque_.push_front(
+        QuicInterval<QuicPacketNumber>(lower, higher));
+    return;
+  }
+  QuicInterval<QuicPacketNumber> back = packet_number_deque_.back();
+
+  if (back.max() == lower) {
+    // Check for the typical case,
+    // when the next packet in order is acked
+    packet_number_deque_.back().SetMax(higher);
+    return;
+  }
+  if (back.max() < lower) {
+    // Check if the next packet in order is skipped
+    packet_number_deque_.push_back(
+        QuicInterval<QuicPacketNumber>(lower, higher));
+    return;
+  }
+  QuicInterval<QuicPacketNumber> front = packet_number_deque_.front();
+  // Check if the packets are being added in reverse order
+  if (front.min() == higher) {
+    packet_number_deque_.front().SetMin(lower);
+  } else if (front.min() > higher) {
+    packet_number_deque_.push_front(
+        QuicInterval<QuicPacketNumber>(lower, higher));
+
+  } else {
+    // Ranges must be above or below all existing ranges.
+    QUIC_BUG << "AddRange only supports adding packets above or below the "
+             << "current min:" << Min() << " and max:" << Max()
+             << ", but adding [" << lower << "," << higher << ")";
+  }
+}
+
+bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) {
+  if (!higher.IsInitialized() || Empty()) {
+    return false;
+  }
+  const QuicPacketNumber old_min = Min();
+  while (!packet_number_deque_.empty()) {
+    QuicInterval<QuicPacketNumber> front = packet_number_deque_.front();
+    if (front.max() < higher) {
+      packet_number_deque_.pop_front();
+    } else if (front.min() < higher && front.max() >= higher) {
+      packet_number_deque_.front().SetMin(higher);
+      if (front.max() == higher) {
+        packet_number_deque_.pop_front();
+      }
+      break;
+    } else {
+      break;
+    }
+  }
+
+  return Empty() || old_min != Min();
+}
+
+void PacketNumberQueue::RemoveSmallestInterval() {
+  QUIC_BUG_IF(packet_number_deque_.size() < 2)
+      << (Empty() ? "No intervals to remove."
+                  : "Can't remove the last interval.");
+  packet_number_deque_.pop_front();
+}
+
+void PacketNumberQueue::Clear() {
+  packet_number_deque_.clear();
+}
+
+bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const {
+  if (!packet_number.IsInitialized() || packet_number_deque_.empty()) {
+    return false;
+  }
+  if (packet_number_deque_.front().min() > packet_number ||
+      packet_number_deque_.back().max() <= packet_number) {
+    return false;
+  }
+  for (QuicInterval<QuicPacketNumber> interval : packet_number_deque_) {
+    if (interval.Contains(packet_number)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool PacketNumberQueue::Empty() const {
+  return packet_number_deque_.empty();
+}
+
+QuicPacketNumber PacketNumberQueue::Min() const {
+  DCHECK(!Empty());
+  return packet_number_deque_.front().min();
+}
+
+QuicPacketNumber PacketNumberQueue::Max() const {
+  DCHECK(!Empty());
+  return packet_number_deque_.back().max() - 1;
+}
+
+QuicPacketCount PacketNumberQueue::NumPacketsSlow() const {
+  QuicPacketCount n_packets = 0;
+  for (QuicInterval<QuicPacketNumber> interval : packet_number_deque_) {
+    n_packets += PacketNumberIntervalLength(interval);
+  }
+  return n_packets;
+}
+
+size_t PacketNumberQueue::NumIntervals() const {
+  return packet_number_deque_.size();
+}
+
+PacketNumberQueue::const_iterator PacketNumberQueue::begin() const {
+  return packet_number_deque_.begin();
+}
+
+PacketNumberQueue::const_iterator PacketNumberQueue::end() const {
+  return packet_number_deque_.end();
+}
+
+PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rbegin() const {
+  return packet_number_deque_.rbegin();
+}
+
+PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rend() const {
+  return packet_number_deque_.rend();
+}
+
+QuicPacketCount PacketNumberQueue::LastIntervalLength() const {
+  DCHECK(!Empty());
+  return PacketNumberIntervalLength(packet_number_deque_.back());
+}
+
+// Largest min...max range for packet numbers where we print the numbers
+// explicitly. If bigger than this, we print as a range  [a,d] rather
+// than [a b c d]
+
+std::ostream& operator<<(std::ostream& os, const PacketNumberQueue& q) {
+  for (const QuicInterval<QuicPacketNumber>& interval : q) {
+    // Print as a range if there is a pathological condition.
+    if ((interval.min() >= interval.max()) ||
+        (interval.max() - interval.min() > kMaxPrintRange)) {
+      // If min>max, it's really a bug, so QUIC_BUG it to
+      // catch it in development.
+      QUIC_BUG_IF(interval.min() >= interval.max())
+          << "Ack Range minimum (" << interval.min() << "Not less than max ("
+          << interval.max() << ")";
+      // print range as min...max rather than full list.
+      // in the event of a bug, the list could be very big.
+      os << interval.min() << "..." << (interval.max() - 1) << " ";
+    } else {
+      for (QuicPacketNumber packet_number = interval.min();
+           packet_number < interval.max(); ++packet_number) {
+        os << packet_number << " ";
+      }
+    }
+  }
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_ack_frame.h b/quic/core/frames/quic_ack_frame.h
new file mode 100644
index 0000000..771d93e
--- /dev/null
+++ b/quic/core/frames/quic_ack_frame.h
@@ -0,0 +1,144 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_interval.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+
+namespace quic {
+
+// A sequence of packet numbers where each number is unique. Intended to be used
+// in a sliding window fashion, where smaller old packet numbers are removed and
+// larger new packet numbers are added, with the occasional random access.
+class QUIC_EXPORT_PRIVATE PacketNumberQueue {
+ public:
+  PacketNumberQueue();
+  PacketNumberQueue(const PacketNumberQueue& other);
+  PacketNumberQueue(PacketNumberQueue&& other);
+  ~PacketNumberQueue();
+
+  PacketNumberQueue& operator=(const PacketNumberQueue& other);
+  PacketNumberQueue& operator=(PacketNumberQueue&& other);
+
+  typedef QuicDeque<QuicInterval<QuicPacketNumber>>::const_iterator
+      const_iterator;
+  typedef QuicDeque<QuicInterval<QuicPacketNumber>>::const_reverse_iterator
+      const_reverse_iterator;
+
+  // Adds |packet_number| to the set of packets in the queue.
+  void Add(QuicPacketNumber packet_number);
+
+  // Adds packets between [lower, higher) to the set of packets in the queue. It
+  // is undefined behavior to call this with |higher| < |lower|.
+  void AddRange(QuicPacketNumber lower, QuicPacketNumber higher);
+
+  // Removes packets with values less than |higher| from the set of packets in
+  // the queue. Returns true if packets were removed.
+  bool RemoveUpTo(QuicPacketNumber higher);
+
+  // Removes the smallest interval in the queue.
+  void RemoveSmallestInterval();
+
+  // Clear this packet number queue.
+  void Clear();
+
+  // Returns true if the queue contains |packet_number|.
+  bool Contains(QuicPacketNumber packet_number) const;
+
+  // Returns true if the queue is empty.
+  bool Empty() const;
+
+  // Returns the minimum packet number stored in the queue. It is undefined
+  // behavior to call this if the queue is empty.
+  QuicPacketNumber Min() const;
+
+  // Returns the maximum packet number stored in the queue. It is undefined
+  // behavior to call this if the queue is empty.
+  QuicPacketNumber Max() const;
+
+  // Returns the number of unique packets stored in the queue. Inefficient; only
+  // exposed for testing.
+  QuicPacketCount NumPacketsSlow() const;
+
+  // Returns the number of disjoint packet number intervals contained in the
+  // queue.
+  size_t NumIntervals() const;
+
+  // Returns the length of last interval.
+  QuicPacketCount LastIntervalLength() const;
+
+  // Returns iterators over the packet number intervals.
+  const_iterator begin() const;
+  const_iterator end() const;
+  const_reverse_iterator rbegin() const;
+  const_reverse_iterator rend() const;
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const PacketNumberQueue& q);
+
+ private:
+  QuicDeque<QuicInterval<QuicPacketNumber>> packet_number_deque_;
+};
+
+struct QUIC_EXPORT_PRIVATE QuicAckFrame {
+  QuicAckFrame();
+  QuicAckFrame(const QuicAckFrame& other);
+  ~QuicAckFrame();
+
+  void Clear();
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicAckFrame& ack_frame);
+
+  // The highest packet number we've observed from the peer. When |packets| is
+  // not empty, it should always be equal to packets.Max(). The |LargestAcked|
+  // function ensures this invariant in debug mode.
+  QuicPacketNumber largest_acked;
+
+  // Time elapsed since largest_observed() was received until this Ack frame was
+  // sent.
+  QuicTime::Delta ack_delay_time;
+
+  // Vector of <packet_number, time> for when packets arrived.
+  PacketTimeVector received_packet_times;
+
+  // Set of packets.
+  PacketNumberQueue packets;
+
+  // ECN counters, used only in version 99's ACK frame and valid only when
+  // |ecn_counters_populated| is true.
+  bool ecn_counters_populated;
+  QuicPacketCount ect_0_count;
+  QuicPacketCount ect_1_count;
+  QuicPacketCount ecn_ce_count;
+};
+
+// The highest acked packet number we've observed from the peer. If no packets
+// have been observed, return 0.
+inline QUIC_EXPORT_PRIVATE QuicPacketNumber
+LargestAcked(const QuicAckFrame& frame) {
+  DCHECK(frame.packets.Empty() || frame.packets.Max() == frame.largest_acked);
+  return frame.largest_acked;
+}
+
+// True if the packet number is greater than largest_observed or is listed
+// as missing.
+// Always returns false for packet numbers less than least_unacked.
+QUIC_EXPORT_PRIVATE bool IsAwaitingPacket(
+    const QuicAckFrame& ack_frame,
+    QuicPacketNumber packet_number,
+    QuicPacketNumber peer_least_packet_awaiting_ack);
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FRAME_H_
diff --git a/quic/core/frames/quic_application_close_frame.cc b/quic/core/frames/quic_application_close_frame.cc
new file mode 100644
index 0000000..2535655
--- /dev/null
+++ b/quic/core/frames/quic_application_close_frame.cc
@@ -0,0 +1,19 @@
+// 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/frames/quic_application_close_frame.h"
+
+namespace quic {
+
+QuicApplicationCloseFrame::QuicApplicationCloseFrame()
+    : error_code(QUIC_NO_ERROR) {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicApplicationCloseFrame& frame) {
+  os << "{ error_code: " << frame.error_code << ", error_details: '"
+     << frame.error_details << "' }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_application_close_frame.h b/quic/core/frames/quic_application_close_frame.h
new file mode 100644
index 0000000..b9b84dd
--- /dev/null
+++ b/quic/core/frames/quic_application_close_frame.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_APPLICATION_CLOSE_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_APPLICATION_CLOSE_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicApplicationCloseFrame {
+  QuicApplicationCloseFrame();
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicApplicationCloseFrame& frame);
+
+  QuicErrorCode error_code;
+  QuicString error_details;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_APPLICATION_CLOSE_FRAME_H_
diff --git a/quic/core/frames/quic_blocked_frame.cc b/quic/core/frames/quic_blocked_frame.cc
new file mode 100644
index 0000000..41ba144
--- /dev/null
+++ b/quic/core/frames/quic_blocked_frame.cc
@@ -0,0 +1,31 @@
+// 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/frames/quic_blocked_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+
+namespace quic {
+
+QuicBlockedFrame::QuicBlockedFrame()
+    : control_frame_id(kInvalidControlFrameId), stream_id(0), offset(0) {}
+
+QuicBlockedFrame::QuicBlockedFrame(QuicControlFrameId control_frame_id,
+                                   QuicStreamId stream_id)
+    : control_frame_id(control_frame_id), stream_id(stream_id), offset(0) {}
+
+QuicBlockedFrame::QuicBlockedFrame(QuicControlFrameId control_frame_id,
+                                   QuicStreamId stream_id,
+                                   QuicStreamOffset offset)
+    : control_frame_id(control_frame_id),
+      stream_id(stream_id),
+      offset(offset) {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicBlockedFrame& blocked_frame) {
+  os << "{ control_frame_id: " << blocked_frame.control_frame_id
+     << ", stream_id: " << blocked_frame.stream_id << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_blocked_frame.h b/quic/core/frames/quic_blocked_frame.h
new file mode 100644
index 0000000..a4be664
--- /dev/null
+++ b/quic/core/frames/quic_blocked_frame.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_BLOCKED_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_BLOCKED_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+
+namespace quic {
+
+// The BLOCKED frame is used to indicate to the remote endpoint that this
+// endpoint believes itself to be flow-control blocked but otherwise ready to
+// send data. The BLOCKED frame is purely advisory and optional.
+// Based on SPDY's BLOCKED frame (undocumented as of 2014-01-28).
+struct QUIC_EXPORT_PRIVATE QuicBlockedFrame {
+  QuicBlockedFrame();
+  QuicBlockedFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id);
+  QuicBlockedFrame(QuicControlFrameId control_frame_id,
+                   QuicStreamId stream_id,
+                   QuicStreamOffset offset);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicBlockedFrame& b);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+
+  // The stream this frame applies to.  0 is a special case meaning the overall
+  // connection rather than a specific stream.
+  //
+  // For IETF QUIC, the stream_id controls whether an IETF QUIC
+  // BLOCKED or STREAM_BLOCKED frame is generated.
+  // If stream_id is 0 then a BLOCKED frame is generated and transmitted,
+  // if non-0, a STREAM_BLOCKED.
+  // TODO(fkastenholz): This should be converted to use
+  // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
+  // and not rely on 0.
+  QuicStreamId stream_id;
+
+  // For Google QUIC, the offset is ignored.
+  QuicStreamOffset offset;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_BLOCKED_FRAME_H_
diff --git a/quic/core/frames/quic_connection_close_frame.cc b/quic/core/frames/quic_connection_close_frame.cc
new file mode 100644
index 0000000..51969c6
--- /dev/null
+++ b/quic/core/frames/quic_connection_close_frame.cc
@@ -0,0 +1,35 @@
+// 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/frames/quic_connection_close_frame.h"
+
+namespace quic {
+
+QuicConnectionCloseFrame::QuicConnectionCloseFrame()
+    : error_code(QUIC_NO_ERROR), frame_type(0) {}
+
+QuicConnectionCloseFrame::QuicConnectionCloseFrame(QuicErrorCode error_code,
+                                                   QuicString error_details)
+    : error_code(error_code),
+      error_details(std::move(error_details)),
+      frame_type(0) {}
+
+QuicConnectionCloseFrame::QuicConnectionCloseFrame(
+    QuicIetfTransportErrorCodes ietf_error_code,
+    QuicString error_details,
+    uint64_t frame_type)
+    : ietf_error_code(ietf_error_code),
+      error_details(std::move(error_details)),
+      frame_type(frame_type) {}
+
+std::ostream& operator<<(
+    std::ostream& os,
+    const QuicConnectionCloseFrame& connection_close_frame) {
+  os << "{ error_code: " << connection_close_frame.error_code
+     << ", error_details: '" << connection_close_frame.error_details
+     << "', frame_type: " << connection_close_frame.frame_type << "}\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_connection_close_frame.h b/quic/core/frames/quic_connection_close_frame.h
new file mode 100644
index 0000000..2bbbe73
--- /dev/null
+++ b/quic/core/frames/quic_connection_close_frame.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_CONNECTION_CLOSE_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_CONNECTION_CLOSE_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicConnectionCloseFrame {
+  QuicConnectionCloseFrame();
+  QuicConnectionCloseFrame(QuicErrorCode error_code, QuicString error_details);
+  QuicConnectionCloseFrame(QuicIetfTransportErrorCodes ietf_error_code,
+                           QuicString error_details,
+                           uint64_t frame_type);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicConnectionCloseFrame& c);
+
+  // Set error_code or ietf_error_code based on the transport version
+  // currently in use.
+  union {
+    // IETF QUIC has a different set of error codes. Include both
+    // code-sets.
+    QuicErrorCode error_code;
+    QuicIetfTransportErrorCodes ietf_error_code;
+  };
+  QuicString error_details;
+
+  // Contains the type of frame that triggered the connection close. Made a
+  // uint64, as opposed to the QuicIetfFrameType, to support possible
+  // extensions as well as reporting invalid frame types received from the peer.
+  uint64_t frame_type;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_CONNECTION_CLOSE_FRAME_H_
diff --git a/quic/core/frames/quic_crypto_frame.cc b/quic/core/frames/quic_crypto_frame.cc
new file mode 100644
index 0000000..9d602bc
--- /dev/null
+++ b/quic/core/frames/quic_crypto_frame.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2018 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/frames/quic_crypto_frame.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+
+namespace quic {
+
+QuicCryptoFrame::QuicCryptoFrame()
+    : QuicCryptoFrame(ENCRYPTION_NONE, 0, nullptr, 0) {}
+
+QuicCryptoFrame::QuicCryptoFrame(EncryptionLevel level,
+                                 QuicStreamOffset offset,
+                                 QuicPacketLength data_length)
+    : QuicCryptoFrame(level, offset, nullptr, data_length) {}
+
+QuicCryptoFrame::QuicCryptoFrame(EncryptionLevel level,
+                                 QuicStreamOffset offset,
+                                 QuicStringPiece data)
+    : QuicCryptoFrame(level, offset, data.data(), data.length()) {}
+
+QuicCryptoFrame::QuicCryptoFrame(EncryptionLevel level,
+                                 QuicStreamOffset offset,
+                                 const char* data_buffer,
+                                 QuicPacketLength data_length)
+    : level(level),
+      data_length(data_length),
+      data_buffer(data_buffer),
+      offset(offset) {}
+
+QuicCryptoFrame::~QuicCryptoFrame() {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicCryptoFrame& stream_frame) {
+  os << "{ offset: " << stream_frame.offset
+     << ", length: " << stream_frame.data_length << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_crypto_frame.h b/quic/core/frames/quic_crypto_frame.h
new file mode 100644
index 0000000..a3968fe
--- /dev/null
+++ b/quic/core/frames/quic_crypto_frame.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2018 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_CRYPTO_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_CRYPTO_FRAME_H_
+
+#include <memory>
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicCryptoFrame {
+  QuicCryptoFrame();
+  QuicCryptoFrame(EncryptionLevel level,
+                  QuicStreamOffset offset,
+                  QuicPacketLength data_length);
+  QuicCryptoFrame(EncryptionLevel level,
+                  QuicStreamOffset offset,
+                  QuicStringPiece data);
+  ~QuicCryptoFrame();
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+                                                      const QuicCryptoFrame& s);
+
+  // When writing a crypto frame to a packet, the packet must be encrypted at
+  // |level|. When a crypto frame is read, the encryption level of the packet it
+  // was received in is put in |level|.
+  EncryptionLevel level;
+  QuicPacketLength data_length;
+  // When reading, |data_buffer| points to the data that was received in the
+  // frame. |data_buffer| is not used when writing.
+  const char* data_buffer;
+  QuicStreamOffset offset;  // Location of this data in the stream.
+
+  QuicCryptoFrame(EncryptionLevel level,
+                  QuicStreamOffset offset,
+                  const char* data_buffer,
+                  QuicPacketLength data_length);
+};
+static_assert(sizeof(QuicCryptoFrame) <= 64,
+              "Keep the QuicCryptoFrame size to a cacheline.");
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_CRYPTO_FRAME_H_
diff --git a/quic/core/frames/quic_frame.cc b/quic/core/frames/quic_frame.cc
new file mode 100644
index 0000000..fbe54cd
--- /dev/null
+++ b/quic/core/frames/quic_frame.cc
@@ -0,0 +1,349 @@
+// 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/frames/quic_frame.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+
+namespace quic {
+
+QuicFrame::QuicFrame() {}
+
+QuicFrame::QuicFrame(QuicPaddingFrame padding_frame)
+    : padding_frame(padding_frame) {}
+
+QuicFrame::QuicFrame(QuicStreamFrame stream_frame)
+    : stream_frame(stream_frame) {}
+
+QuicFrame::QuicFrame(QuicCryptoFrame* crypto_frame)
+    : type(CRYPTO_FRAME), crypto_frame(crypto_frame) {}
+
+QuicFrame::QuicFrame(QuicAckFrame* frame) : type(ACK_FRAME), ack_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicMtuDiscoveryFrame frame)
+    : mtu_discovery_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicStopWaitingFrame frame) : stop_waiting_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicPingFrame frame) : ping_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicRstStreamFrame* frame)
+    : type(RST_STREAM_FRAME), rst_stream_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicConnectionCloseFrame* frame)
+    : type(CONNECTION_CLOSE_FRAME), connection_close_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicGoAwayFrame* frame)
+    : type(GOAWAY_FRAME), goaway_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicWindowUpdateFrame* frame)
+    : type(WINDOW_UPDATE_FRAME), window_update_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicBlockedFrame* frame)
+    : type(BLOCKED_FRAME), blocked_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicApplicationCloseFrame* frame)
+    : type(APPLICATION_CLOSE_FRAME), application_close_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicNewConnectionIdFrame* frame)
+    : type(NEW_CONNECTION_ID_FRAME), new_connection_id_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicRetireConnectionIdFrame* frame)
+    : type(RETIRE_CONNECTION_ID_FRAME), retire_connection_id_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicMaxStreamIdFrame frame) : max_stream_id_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicStreamIdBlockedFrame frame)
+    : stream_id_blocked_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicPathResponseFrame* frame)
+    : type(PATH_RESPONSE_FRAME), path_response_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicPathChallengeFrame* frame)
+    : type(PATH_CHALLENGE_FRAME), path_challenge_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicStopSendingFrame* frame)
+    : type(STOP_SENDING_FRAME), stop_sending_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicMessageFrame* frame)
+    : type(MESSAGE_FRAME), message_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicNewTokenFrame* frame)
+    : type(NEW_TOKEN_FRAME), new_token_frame(frame) {}
+
+void DeleteFrames(QuicFrames* frames) {
+  for (QuicFrame& frame : *frames) {
+    DeleteFrame(&frame);
+  }
+  frames->clear();
+}
+
+void DeleteFrame(QuicFrame* frame) {
+  switch (frame->type) {
+    // Frames smaller than a pointer are inlined, so don't need to be deleted.
+    case PADDING_FRAME:
+    case MTU_DISCOVERY_FRAME:
+    case PING_FRAME:
+    case MAX_STREAM_ID_FRAME:
+    case STOP_WAITING_FRAME:
+    case STREAM_ID_BLOCKED_FRAME:
+    case STREAM_FRAME:
+      break;
+    case ACK_FRAME:
+      delete frame->ack_frame;
+      break;
+    case RST_STREAM_FRAME:
+      delete frame->rst_stream_frame;
+      break;
+    case CONNECTION_CLOSE_FRAME:
+      delete frame->connection_close_frame;
+      break;
+    case GOAWAY_FRAME:
+      delete frame->goaway_frame;
+      break;
+    case BLOCKED_FRAME:
+      delete frame->blocked_frame;
+      break;
+    case WINDOW_UPDATE_FRAME:
+      delete frame->window_update_frame;
+      break;
+    case PATH_CHALLENGE_FRAME:
+      delete frame->path_challenge_frame;
+      break;
+    case STOP_SENDING_FRAME:
+      delete frame->stop_sending_frame;
+      break;
+    case APPLICATION_CLOSE_FRAME:
+      delete frame->application_close_frame;
+      break;
+    case NEW_CONNECTION_ID_FRAME:
+      delete frame->new_connection_id_frame;
+      break;
+    case RETIRE_CONNECTION_ID_FRAME:
+      delete frame->retire_connection_id_frame;
+      break;
+    case PATH_RESPONSE_FRAME:
+      delete frame->path_response_frame;
+      break;
+    case MESSAGE_FRAME:
+      delete frame->message_frame;
+      break;
+    case CRYPTO_FRAME:
+      delete frame->crypto_frame;
+      break;
+    case NEW_TOKEN_FRAME:
+      delete frame->new_token_frame;
+      break;
+
+    case NUM_FRAME_TYPES:
+      DCHECK(false) << "Cannot delete type: " << frame->type;
+  }
+}
+
+void RemoveFramesForStream(QuicFrames* frames, QuicStreamId stream_id) {
+  auto it = frames->begin();
+  while (it != frames->end()) {
+    if (it->type != STREAM_FRAME || it->stream_frame.stream_id != stream_id) {
+      ++it;
+      continue;
+    }
+    it = frames->erase(it);
+  }
+}
+
+bool IsControlFrame(QuicFrameType type) {
+  switch (type) {
+    case RST_STREAM_FRAME:
+    case GOAWAY_FRAME:
+    case WINDOW_UPDATE_FRAME:
+    case BLOCKED_FRAME:
+    case STREAM_ID_BLOCKED_FRAME:
+    case MAX_STREAM_ID_FRAME:
+    case PING_FRAME:
+    case STOP_SENDING_FRAME:
+      return true;
+    default:
+      return false;
+  }
+}
+
+QuicControlFrameId GetControlFrameId(const QuicFrame& frame) {
+  switch (frame.type) {
+    case RST_STREAM_FRAME:
+      return frame.rst_stream_frame->control_frame_id;
+    case GOAWAY_FRAME:
+      return frame.goaway_frame->control_frame_id;
+    case WINDOW_UPDATE_FRAME:
+      return frame.window_update_frame->control_frame_id;
+    case BLOCKED_FRAME:
+      return frame.blocked_frame->control_frame_id;
+    case STREAM_ID_BLOCKED_FRAME:
+      return frame.stream_id_blocked_frame.control_frame_id;
+    case MAX_STREAM_ID_FRAME:
+      return frame.max_stream_id_frame.control_frame_id;
+    case PING_FRAME:
+      return frame.ping_frame.control_frame_id;
+    case STOP_SENDING_FRAME:
+      return frame.stop_sending_frame->control_frame_id;
+    default:
+      return kInvalidControlFrameId;
+  }
+}
+
+void SetControlFrameId(QuicControlFrameId control_frame_id, QuicFrame* frame) {
+  switch (frame->type) {
+    case RST_STREAM_FRAME:
+      frame->rst_stream_frame->control_frame_id = control_frame_id;
+      return;
+    case GOAWAY_FRAME:
+      frame->goaway_frame->control_frame_id = control_frame_id;
+      return;
+    case WINDOW_UPDATE_FRAME:
+      frame->window_update_frame->control_frame_id = control_frame_id;
+      return;
+    case BLOCKED_FRAME:
+      frame->blocked_frame->control_frame_id = control_frame_id;
+      return;
+    case PING_FRAME:
+      frame->ping_frame.control_frame_id = control_frame_id;
+      return;
+    case STREAM_ID_BLOCKED_FRAME:
+      frame->stream_id_blocked_frame.control_frame_id = control_frame_id;
+      return;
+    case MAX_STREAM_ID_FRAME:
+      frame->max_stream_id_frame.control_frame_id = control_frame_id;
+      return;
+    case STOP_SENDING_FRAME:
+      frame->stop_sending_frame->control_frame_id = control_frame_id;
+      return;
+    default:
+      QUIC_BUG
+          << "Try to set control frame id of a frame without control frame id";
+  }
+}
+
+QuicFrame CopyRetransmittableControlFrame(const QuicFrame& frame) {
+  QuicFrame copy;
+  switch (frame.type) {
+    case RST_STREAM_FRAME:
+      copy = QuicFrame(new QuicRstStreamFrame(*frame.rst_stream_frame));
+      break;
+    case GOAWAY_FRAME:
+      copy = QuicFrame(new QuicGoAwayFrame(*frame.goaway_frame));
+      break;
+    case WINDOW_UPDATE_FRAME:
+      copy = QuicFrame(new QuicWindowUpdateFrame(*frame.window_update_frame));
+      break;
+    case BLOCKED_FRAME:
+      copy = QuicFrame(new QuicBlockedFrame(*frame.blocked_frame));
+      break;
+    case PING_FRAME:
+      copy = QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id));
+      break;
+    case STOP_SENDING_FRAME:
+      copy = QuicFrame(new QuicStopSendingFrame(*frame.stop_sending_frame));
+      break;
+    case STREAM_ID_BLOCKED_FRAME:
+      copy = QuicFrame(QuicStreamIdBlockedFrame(frame.stream_id_blocked_frame));
+      break;
+    case MAX_STREAM_ID_FRAME:
+      copy = QuicFrame(QuicMaxStreamIdFrame(frame.max_stream_id_frame));
+      break;
+    default:
+      QUIC_BUG << "Try to copy a non-retransmittable control frame: " << frame;
+      copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId));
+      break;
+  }
+  return copy;
+}
+
+std::ostream& operator<<(std::ostream& os, const QuicFrame& frame) {
+  switch (frame.type) {
+    case PADDING_FRAME: {
+      os << "type { PADDING_FRAME } " << frame.padding_frame;
+      break;
+    }
+    case RST_STREAM_FRAME: {
+      os << "type { RST_STREAM_FRAME } " << *(frame.rst_stream_frame);
+      break;
+    }
+    case CONNECTION_CLOSE_FRAME: {
+      os << "type { CONNECTION_CLOSE_FRAME } "
+         << *(frame.connection_close_frame);
+      break;
+    }
+    case GOAWAY_FRAME: {
+      os << "type { GOAWAY_FRAME } " << *(frame.goaway_frame);
+      break;
+    }
+    case WINDOW_UPDATE_FRAME: {
+      os << "type { WINDOW_UPDATE_FRAME } " << *(frame.window_update_frame);
+      break;
+    }
+    case BLOCKED_FRAME: {
+      os << "type { BLOCKED_FRAME } " << *(frame.blocked_frame);
+      break;
+    }
+    case STREAM_FRAME: {
+      os << "type { STREAM_FRAME } " << frame.stream_frame;
+      break;
+    }
+    case ACK_FRAME: {
+      os << "type { ACK_FRAME } " << *(frame.ack_frame);
+      break;
+    }
+    case STOP_WAITING_FRAME: {
+      os << "type { STOP_WAITING_FRAME } " << frame.stop_waiting_frame;
+      break;
+    }
+    case PING_FRAME: {
+      os << "type { PING_FRAME } " << frame.ping_frame;
+      break;
+    }
+    case MTU_DISCOVERY_FRAME: {
+      os << "type { MTU_DISCOVERY_FRAME } ";
+      break;
+    }
+    case APPLICATION_CLOSE_FRAME:
+      os << "type { APPLICATION_CLOSE } " << *(frame.application_close_frame);
+      break;
+    case NEW_CONNECTION_ID_FRAME:
+      os << "type { NEW_CONNECTION_ID } " << *(frame.new_connection_id_frame);
+      break;
+    case RETIRE_CONNECTION_ID_FRAME:
+      os << "type { RETIRE_CONNECTION_ID } "
+         << *(frame.retire_connection_id_frame);
+      break;
+    case MAX_STREAM_ID_FRAME:
+      os << "type { MAX_STREAM_ID } " << frame.max_stream_id_frame;
+      break;
+    case STREAM_ID_BLOCKED_FRAME:
+      os << "type { STREAM_ID_BLOCKED } " << frame.stream_id_blocked_frame;
+      break;
+    case PATH_RESPONSE_FRAME:
+      os << "type { PATH_RESPONSE } " << *(frame.path_response_frame);
+      break;
+    case PATH_CHALLENGE_FRAME:
+      os << "type { PATH_CHALLENGE } " << *(frame.path_challenge_frame);
+      break;
+    case STOP_SENDING_FRAME:
+      os << "type { STOP_SENDING } " << *(frame.stop_sending_frame);
+      break;
+    case MESSAGE_FRAME:
+      os << "type { MESSAGE_FRAME }" << *(frame.message_frame);
+      break;
+    case NEW_TOKEN_FRAME:
+      os << "type { NEW_TOKEN_FRAME }" << *(frame.new_token_frame);
+      break;
+    default: {
+      QUIC_LOG(ERROR) << "Unknown frame type: " << frame.type;
+      break;
+    }
+  }
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_frame.h b/quic/core/frames/quic_frame.h
new file mode 100644
index 0000000..d753862
--- /dev/null
+++ b/quic/core/frames/quic_frame.h
@@ -0,0 +1,148 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_FRAME_H_
+
+#include <ostream>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_application_close_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_max_stream_id_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_message_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_mtu_discovery_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_stop_waiting_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_stream_id_blocked_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicFrame {
+  QuicFrame();
+  // Please keep the constructors in the same order as the union below.
+  explicit QuicFrame(QuicPaddingFrame padding_frame);
+  explicit QuicFrame(QuicMtuDiscoveryFrame frame);
+  explicit QuicFrame(QuicPingFrame frame);
+  explicit QuicFrame(QuicMaxStreamIdFrame frame);
+  explicit QuicFrame(QuicStopWaitingFrame frame);
+  explicit QuicFrame(QuicStreamIdBlockedFrame frame);
+  explicit QuicFrame(QuicStreamFrame stream_frame);
+
+  explicit QuicFrame(QuicAckFrame* frame);
+  explicit QuicFrame(QuicRstStreamFrame* frame);
+  explicit QuicFrame(QuicConnectionCloseFrame* frame);
+  explicit QuicFrame(QuicGoAwayFrame* frame);
+  explicit QuicFrame(QuicWindowUpdateFrame* frame);
+  explicit QuicFrame(QuicBlockedFrame* frame);
+  explicit QuicFrame(QuicApplicationCloseFrame* frame);
+  explicit QuicFrame(QuicNewConnectionIdFrame* frame);
+  explicit QuicFrame(QuicRetireConnectionIdFrame* frame);
+  explicit QuicFrame(QuicNewTokenFrame* frame);
+  explicit QuicFrame(QuicPathResponseFrame* frame);
+  explicit QuicFrame(QuicPathChallengeFrame* frame);
+  explicit QuicFrame(QuicStopSendingFrame* frame);
+  explicit QuicFrame(QuicMessageFrame* message_frame);
+  explicit QuicFrame(QuicCryptoFrame* crypto_frame);
+
+  QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
+                                                      const QuicFrame& frame);
+
+  union {
+    // Inlined frames.
+    // Overlapping inlined frames have a |type| field at the same 0 offset as
+    // QuicFrame does for out of line frames below, allowing use of the
+    // remaining 7 bytes after offset for frame-type specific fields.
+    QuicPaddingFrame padding_frame;
+    QuicMtuDiscoveryFrame mtu_discovery_frame;
+    QuicPingFrame ping_frame;
+    QuicMaxStreamIdFrame max_stream_id_frame;
+    QuicStopWaitingFrame stop_waiting_frame;
+    QuicStreamIdBlockedFrame stream_id_blocked_frame;
+    QuicStreamFrame stream_frame;
+
+    // Out of line frames.
+    struct {
+      QuicFrameType type;
+
+      // TODO(wub): These frames can also be inlined without increasing the size
+      // of QuicFrame: QuicRstStreamFrame, QuicWindowUpdateFrame,
+      // QuicBlockedFrame, QuicPathResponseFrame, QuicPathChallengeFrame and
+      // QuicStopSendingFrame.
+      union {
+        QuicAckFrame* ack_frame;
+        QuicRstStreamFrame* rst_stream_frame;
+        QuicConnectionCloseFrame* connection_close_frame;
+        QuicGoAwayFrame* goaway_frame;
+        QuicWindowUpdateFrame* window_update_frame;
+        QuicBlockedFrame* blocked_frame;
+        QuicApplicationCloseFrame* application_close_frame;
+        QuicNewConnectionIdFrame* new_connection_id_frame;
+        QuicRetireConnectionIdFrame* retire_connection_id_frame;
+        QuicPathResponseFrame* path_response_frame;
+        QuicPathChallengeFrame* path_challenge_frame;
+        QuicStopSendingFrame* stop_sending_frame;
+        QuicMessageFrame* message_frame;
+        QuicCryptoFrame* crypto_frame;
+        QuicNewTokenFrame* new_token_frame;
+      };
+    };
+  };
+};
+
+static_assert(sizeof(QuicFrame) <= 24,
+              "Frames larger than 24 bytes should be referenced by pointer.");
+static_assert(offsetof(QuicStreamFrame, type) == offsetof(QuicFrame, type),
+              "Offset of |type| must match in QuicFrame and QuicStreamFrame");
+
+// A inline size of 1 is chosen to optimize the typical use case of
+// 1-stream-frame in QuicTransmissionInfo.retransmittable_frames.
+typedef QuicInlinedVector<QuicFrame, 1> QuicFrames;
+
+// Deletes all the sub-frames contained in |frames|.
+QUIC_EXPORT_PRIVATE void DeleteFrames(QuicFrames* frames);
+
+// Delete the sub-frame contained in |frame|.
+QUIC_EXPORT_PRIVATE void DeleteFrame(QuicFrame* frame);
+
+// Deletes all the QuicStreamFrames for the specified |stream_id|.
+QUIC_EXPORT_PRIVATE void RemoveFramesForStream(QuicFrames* frames,
+                                               QuicStreamId stream_id);
+
+// Returns true if |type| is a retransmittable control frame.
+QUIC_EXPORT_PRIVATE bool IsControlFrame(QuicFrameType type);
+
+// Returns control_frame_id of |frame|. Returns kInvalidControlFrameId if
+// |frame| does not have a valid control_frame_id.
+QUIC_EXPORT_PRIVATE QuicControlFrameId
+GetControlFrameId(const QuicFrame& frame);
+
+// Sets control_frame_id of |frame| to |control_frame_id|.
+QUIC_EXPORT_PRIVATE void SetControlFrameId(QuicControlFrameId control_frame_id,
+                                           QuicFrame* frame);
+
+// Returns a copy of |frame|.
+QUIC_EXPORT_PRIVATE QuicFrame
+CopyRetransmittableControlFrame(const QuicFrame& frame);
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_FRAME_H_
diff --git a/quic/core/frames/quic_frames_test.cc b/quic/core/frames/quic_frames_test.cc
new file mode 100644
index 0000000..986b3c5
--- /dev/null
+++ b/quic/core/frames/quic_frames_test.cc
@@ -0,0 +1,638 @@
+// 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/frames/quic_ack_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_mtu_discovery_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_stop_waiting_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+class QuicFramesTest : public QuicTest {};
+
+TEST_F(QuicFramesTest, AckFrameToString) {
+  QuicAckFrame frame;
+  frame.largest_acked = QuicPacketNumber(5);
+  frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3);
+  frame.packets.Add(QuicPacketNumber(4));
+  frame.packets.Add(QuicPacketNumber(5));
+  frame.received_packet_times = {
+      {QuicPacketNumber(6),
+       QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
+  std::ostringstream stream;
+  stream << frame;
+  EXPECT_EQ(
+      "{ largest_acked: 5, ack_delay_time: 3, packets: [ 4 5  ], "
+      "received_packets: [ 6 at 7  ], ecn_counters_populated: 0 }\n",
+      stream.str());
+  QuicFrame quic_frame(&frame);
+  EXPECT_FALSE(IsControlFrame(quic_frame.type));
+}
+
+TEST_F(QuicFramesTest, BigAckFrameToString) {
+  QuicAckFrame frame;
+  frame.largest_acked = QuicPacketNumber(500);
+  frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3);
+  frame.packets.AddRange(QuicPacketNumber(4), QuicPacketNumber(501));
+  frame.received_packet_times = {
+      {QuicPacketNumber(500),
+       QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
+  std::ostringstream stream;
+  stream << frame;
+  EXPECT_EQ(
+      "{ largest_acked: 500, ack_delay_time: 3, packets: [ 4...500  ], "
+      "received_packets: [ 500 at 7  ], ecn_counters_populated: 0 }\n",
+      stream.str());
+  QuicFrame quic_frame(&frame);
+  EXPECT_FALSE(IsControlFrame(quic_frame.type));
+}
+
+TEST_F(QuicFramesTest, PaddingFrameToString) {
+  QuicPaddingFrame frame;
+  frame.num_padding_bytes = 1;
+  std::ostringstream stream;
+  stream << frame;
+  EXPECT_EQ("{ num_padding_bytes: 1 }\n", stream.str());
+  QuicFrame quic_frame(frame);
+  EXPECT_FALSE(IsControlFrame(quic_frame.type));
+}
+
+TEST_F(QuicFramesTest, RstStreamFrameToString) {
+  QuicRstStreamFrame rst_stream;
+  QuicFrame frame(&rst_stream);
+  SetControlFrameId(1, &frame);
+  EXPECT_EQ(1u, GetControlFrameId(frame));
+  rst_stream.stream_id = 1;
+  rst_stream.error_code = QUIC_STREAM_CANCELLED;
+  std::ostringstream stream;
+  stream << rst_stream;
+  EXPECT_EQ("{ control_frame_id: 1, stream_id: 1, error_code: 6 }\n",
+            stream.str());
+  EXPECT_TRUE(IsControlFrame(frame.type));
+}
+
+TEST_F(QuicFramesTest, StopSendingFrameToString) {
+  QuicStopSendingFrame stop_sending;
+  QuicFrame frame(&stop_sending);
+  SetControlFrameId(1, &frame);
+  EXPECT_EQ(1u, GetControlFrameId(frame));
+  stop_sending.stream_id = 321;
+  stop_sending.application_error_code = QUIC_STREAM_CANCELLED;
+  std::ostringstream stream;
+  stream << stop_sending;
+  EXPECT_EQ(
+      "{ control_frame_id: 1, stream_id: 321, application_error_code: 6 }\n",
+      stream.str());
+  EXPECT_TRUE(IsControlFrame(frame.type));
+}
+
+TEST_F(QuicFramesTest, StreamIdBlockedFrameToString) {
+  QuicStreamIdBlockedFrame stream_id_blocked;
+  QuicFrame frame(stream_id_blocked);
+  SetControlFrameId(1, &frame);
+  EXPECT_EQ(1u, GetControlFrameId(frame));
+  // QuicStreamIdBlocked is copied into a QuicFrame (as opposed to putting a
+  // pointer to it into QuicFrame) so need to work with the copy in |frame| and
+  // not the original one, stream_id_blocked.
+  frame.stream_id_blocked_frame.stream_id = 321;
+  std::ostringstream stream;
+  stream << frame.stream_id_blocked_frame;
+  EXPECT_EQ("{ control_frame_id: 1, stream id: 321 }\n", stream.str());
+  EXPECT_TRUE(IsControlFrame(frame.type));
+}
+
+TEST_F(QuicFramesTest, MaxStreamIdFrameToString) {
+  QuicMaxStreamIdFrame max_stream_id;
+  QuicFrame frame(max_stream_id);
+  SetControlFrameId(1, &frame);
+  EXPECT_EQ(1u, GetControlFrameId(frame));
+  // QuicMaxStreamId is copied into a QuicFrame (as opposed to putting a
+  // pointer to it into QuicFrame) so need to work with the copy in |frame| and
+  // not the original one, max_stream_id.
+  frame.max_stream_id_frame.max_stream_id = 321;
+  std::ostringstream stream;
+  stream << frame.max_stream_id_frame;
+  EXPECT_EQ("{ control_frame_id: 1, stream_id: 321 }\n", stream.str());
+  EXPECT_TRUE(IsControlFrame(frame.type));
+}
+
+TEST_F(QuicFramesTest, ConnectionCloseFrameToString) {
+  QuicConnectionCloseFrame frame;
+  frame.error_code = QUIC_NETWORK_IDLE_TIMEOUT;
+  frame.error_details = "No recent network activity.";
+  std::ostringstream stream;
+  stream << frame;
+  EXPECT_EQ(
+      "{ error_code: 25, error_details: 'No recent network activity.', "
+      "frame_type: 0"
+      "}\n",
+      stream.str());
+  QuicFrame quic_frame(&frame);
+  EXPECT_FALSE(IsControlFrame(quic_frame.type));
+}
+
+TEST_F(QuicFramesTest, GoAwayFrameToString) {
+  QuicGoAwayFrame goaway_frame;
+  QuicFrame frame(&goaway_frame);
+  SetControlFrameId(2, &frame);
+  EXPECT_EQ(2u, GetControlFrameId(frame));
+  goaway_frame.error_code = QUIC_NETWORK_IDLE_TIMEOUT;
+  goaway_frame.last_good_stream_id = 2;
+  goaway_frame.reason_phrase = "Reason";
+  std::ostringstream stream;
+  stream << goaway_frame;
+  EXPECT_EQ(
+      "{ control_frame_id: 2, error_code: 25, last_good_stream_id: 2, "
+      "reason_phrase: "
+      "'Reason' }\n",
+      stream.str());
+  EXPECT_TRUE(IsControlFrame(frame.type));
+}
+
+TEST_F(QuicFramesTest, WindowUpdateFrameToString) {
+  QuicWindowUpdateFrame window_update;
+  QuicFrame frame(&window_update);
+  SetControlFrameId(3, &frame);
+  EXPECT_EQ(3u, GetControlFrameId(frame));
+  std::ostringstream stream;
+  window_update.stream_id = 1;
+  window_update.byte_offset = 2;
+  stream << window_update;
+  EXPECT_EQ("{ control_frame_id: 3, stream_id: 1, byte_offset: 2 }\n",
+            stream.str());
+  EXPECT_TRUE(IsControlFrame(frame.type));
+}
+
+TEST_F(QuicFramesTest, BlockedFrameToString) {
+  QuicBlockedFrame blocked;
+  QuicFrame frame(&blocked);
+  SetControlFrameId(4, &frame);
+  EXPECT_EQ(4u, GetControlFrameId(frame));
+  blocked.stream_id = 1;
+  std::ostringstream stream;
+  stream << blocked;
+  EXPECT_EQ("{ control_frame_id: 4, stream_id: 1 }\n", stream.str());
+  EXPECT_TRUE(IsControlFrame(frame.type));
+}
+
+TEST_F(QuicFramesTest, PingFrameToString) {
+  QuicPingFrame ping;
+  QuicFrame frame(ping);
+  SetControlFrameId(5, &frame);
+  EXPECT_EQ(5u, GetControlFrameId(frame));
+  std::ostringstream stream;
+  stream << frame.ping_frame;
+  EXPECT_EQ("{ control_frame_id: 5 }\n", stream.str());
+  EXPECT_TRUE(IsControlFrame(frame.type));
+}
+
+TEST_F(QuicFramesTest, StreamFrameToString) {
+  QuicStreamFrame frame;
+  frame.stream_id = 1;
+  frame.fin = false;
+  frame.offset = 2;
+  frame.data_length = 3;
+  std::ostringstream stream;
+  stream << frame;
+  EXPECT_EQ("{ stream_id: 1, fin: 0, offset: 2, length: 3 }\n", stream.str());
+  EXPECT_FALSE(IsControlFrame(frame.type));
+}
+
+TEST_F(QuicFramesTest, StopWaitingFrameToString) {
+  QuicStopWaitingFrame frame;
+  frame.least_unacked = QuicPacketNumber(2);
+  std::ostringstream stream;
+  stream << frame;
+  EXPECT_EQ("{ least_unacked: 2 }\n", stream.str());
+  QuicFrame quic_frame(frame);
+  EXPECT_FALSE(IsControlFrame(quic_frame.type));
+}
+
+TEST_F(QuicFramesTest, IsAwaitingPacket) {
+  QuicAckFrame ack_frame1;
+  ack_frame1.largest_acked = QuicPacketNumber(10u);
+  ack_frame1.packets.AddRange(QuicPacketNumber(1), QuicPacketNumber(11));
+  EXPECT_TRUE(
+      IsAwaitingPacket(ack_frame1, QuicPacketNumber(11u), QuicPacketNumber()));
+  EXPECT_FALSE(
+      IsAwaitingPacket(ack_frame1, QuicPacketNumber(1u), QuicPacketNumber()));
+
+  ack_frame1.packets.Add(QuicPacketNumber(12));
+  EXPECT_TRUE(
+      IsAwaitingPacket(ack_frame1, QuicPacketNumber(11u), QuicPacketNumber()));
+
+  QuicAckFrame ack_frame2;
+  ack_frame2.largest_acked = QuicPacketNumber(100u);
+  ack_frame2.packets.AddRange(QuicPacketNumber(21), QuicPacketNumber(100));
+  EXPECT_FALSE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(11u),
+                                QuicPacketNumber(20u)));
+  EXPECT_FALSE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(80u),
+                                QuicPacketNumber(20u)));
+  EXPECT_TRUE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(101u),
+                               QuicPacketNumber(20u)));
+
+  ack_frame2.packets.AddRange(QuicPacketNumber(102), QuicPacketNumber(200));
+  EXPECT_TRUE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(101u),
+                               QuicPacketNumber(20u)));
+}
+
+TEST_F(QuicFramesTest, AddPacket) {
+  QuicAckFrame ack_frame1;
+  ack_frame1.packets.Add(QuicPacketNumber(1));
+  ack_frame1.packets.Add(QuicPacketNumber(99));
+
+  EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
+  EXPECT_EQ(QuicPacketNumber(1u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
+
+  std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
+  expected_intervals.emplace_back(
+      QuicInterval<QuicPacketNumber>(QuicPacketNumber(1), QuicPacketNumber(2)));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(99), QuicPacketNumber(100)));
+
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  EXPECT_EQ(expected_intervals, actual_intervals);
+
+  ack_frame1.packets.Add(QuicPacketNumber(20));
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  std::vector<QuicInterval<QuicPacketNumber>> expected_intervals2;
+  expected_intervals2.emplace_back(
+      QuicInterval<QuicPacketNumber>(QuicPacketNumber(1), QuicPacketNumber(2)));
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(20), QuicPacketNumber(21)));
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(99), QuicPacketNumber(100)));
+
+  EXPECT_EQ(3u, ack_frame1.packets.NumIntervals());
+  EXPECT_EQ(expected_intervals2, actual_intervals2);
+
+  ack_frame1.packets.Add(QuicPacketNumber(19));
+  ack_frame1.packets.Add(QuicPacketNumber(21));
+
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals3(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  std::vector<QuicInterval<QuicPacketNumber>> expected_intervals3;
+  expected_intervals3.emplace_back(
+      QuicInterval<QuicPacketNumber>(QuicPacketNumber(1), QuicPacketNumber(2)));
+  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(19), QuicPacketNumber(22)));
+  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(99), QuicPacketNumber(100)));
+
+  EXPECT_EQ(expected_intervals3, actual_intervals3);
+
+  ack_frame1.packets.Add(QuicPacketNumber(20));
+
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals4(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  EXPECT_EQ(expected_intervals3, actual_intervals4);
+
+  QuicAckFrame ack_frame2;
+  ack_frame2.packets.Add(QuicPacketNumber(20));
+  ack_frame2.packets.Add(QuicPacketNumber(40));
+  ack_frame2.packets.Add(QuicPacketNumber(60));
+  ack_frame2.packets.Add(QuicPacketNumber(10));
+  ack_frame2.packets.Add(QuicPacketNumber(80));
+
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals5(
+      ack_frame2.packets.begin(), ack_frame2.packets.end());
+
+  std::vector<QuicInterval<QuicPacketNumber>> expected_intervals5;
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(10), QuicPacketNumber(11)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(20), QuicPacketNumber(21)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(40), QuicPacketNumber(41)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(60), QuicPacketNumber(61)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(80), QuicPacketNumber(81)));
+
+  EXPECT_EQ(expected_intervals5, actual_intervals5);
+}
+
+TEST_F(QuicFramesTest, AddInterval) {
+  QuicAckFrame ack_frame1;
+  ack_frame1.packets.AddRange(QuicPacketNumber(1), QuicPacketNumber(10));
+  ack_frame1.packets.AddRange(QuicPacketNumber(50), QuicPacketNumber(100));
+
+  EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
+  EXPECT_EQ(QuicPacketNumber(1u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
+
+  std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(10)));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(50), QuicPacketNumber(100)));
+
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  EXPECT_EQ(expected_intervals, actual_intervals);
+
+  // Ensure adding a range within the existing ranges fails.
+  EXPECT_QUIC_BUG(
+      ack_frame1.packets.AddRange(QuicPacketNumber(20), QuicPacketNumber(30)),
+      "");
+
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  std::vector<QuicInterval<QuicPacketNumber>> expected_intervals2;
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(10)));
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(50), QuicPacketNumber(100)));
+
+  EXPECT_EQ(expected_intervals2.size(), ack_frame1.packets.NumIntervals());
+  EXPECT_EQ(expected_intervals2, actual_intervals2);
+
+  // Add ranges at both ends.
+  QuicAckFrame ack_frame2;
+  ack_frame2.packets.AddRange(QuicPacketNumber(20), QuicPacketNumber(25));
+  ack_frame2.packets.AddRange(QuicPacketNumber(40), QuicPacketNumber(45));
+  ack_frame2.packets.AddRange(QuicPacketNumber(60), QuicPacketNumber(65));
+  ack_frame2.packets.AddRange(QuicPacketNumber(10), QuicPacketNumber(15));
+  ack_frame2.packets.AddRange(QuicPacketNumber(80), QuicPacketNumber(85));
+
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals8(
+      ack_frame2.packets.begin(), ack_frame2.packets.end());
+
+  std::vector<QuicInterval<QuicPacketNumber>> expected_intervals8;
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(10), QuicPacketNumber(15)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(20), QuicPacketNumber(25)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(40), QuicPacketNumber(45)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(60), QuicPacketNumber(65)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(80), QuicPacketNumber(85)));
+
+  EXPECT_EQ(expected_intervals8, actual_intervals8);
+}
+
+TEST_F(QuicFramesTest, AddAdjacentForward) {
+  QuicAckFrame ack_frame1;
+  ack_frame1.packets.Add(QuicPacketNumber(49));
+  ack_frame1.packets.AddRange(QuicPacketNumber(50), QuicPacketNumber(60));
+  ack_frame1.packets.AddRange(QuicPacketNumber(60), QuicPacketNumber(70));
+  ack_frame1.packets.AddRange(QuicPacketNumber(70), QuicPacketNumber(100));
+
+  std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(49), QuicPacketNumber(100)));
+
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  EXPECT_EQ(expected_intervals, actual_intervals);
+}
+
+TEST_F(QuicFramesTest, AddAdjacentReverse) {
+  QuicAckFrame ack_frame1;
+  ack_frame1.packets.AddRange(QuicPacketNumber(70), QuicPacketNumber(100));
+  ack_frame1.packets.AddRange(QuicPacketNumber(60), QuicPacketNumber(70));
+  ack_frame1.packets.AddRange(QuicPacketNumber(50), QuicPacketNumber(60));
+  ack_frame1.packets.Add(QuicPacketNumber(49));
+
+  std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(49), QuicPacketNumber(100)));
+
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  EXPECT_EQ(expected_intervals, actual_intervals);
+}
+
+TEST_F(QuicFramesTest, RemoveSmallestInterval) {
+  QuicAckFrame ack_frame1;
+  ack_frame1.largest_acked = QuicPacketNumber(100u);
+  ack_frame1.packets.AddRange(QuicPacketNumber(51), QuicPacketNumber(60));
+  ack_frame1.packets.AddRange(QuicPacketNumber(71), QuicPacketNumber(80));
+  ack_frame1.packets.AddRange(QuicPacketNumber(91), QuicPacketNumber(100));
+  ack_frame1.packets.RemoveSmallestInterval();
+  EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
+  EXPECT_EQ(QuicPacketNumber(71u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
+
+  ack_frame1.packets.RemoveSmallestInterval();
+  EXPECT_EQ(1u, ack_frame1.packets.NumIntervals());
+  EXPECT_EQ(QuicPacketNumber(91u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
+}
+
+class PacketNumberQueueTest : public QuicTest {};
+
+// Tests that a queue contains the expected data after calls to Add().
+TEST_F(PacketNumberQueueTest, AddRange) {
+  PacketNumberQueue queue;
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(51));
+  queue.Add(QuicPacketNumber(53));
+
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber()));
+  for (int i = 1; i < 51; ++i) {
+    EXPECT_TRUE(queue.Contains(QuicPacketNumber(i)));
+  }
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(51)));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(52)));
+  EXPECT_TRUE(queue.Contains(QuicPacketNumber(53)));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(54)));
+  EXPECT_EQ(51u, queue.NumPacketsSlow());
+  EXPECT_EQ(QuicPacketNumber(1u), queue.Min());
+  EXPECT_EQ(QuicPacketNumber(53u), queue.Max());
+
+  queue.Add(QuicPacketNumber(70));
+  EXPECT_EQ(QuicPacketNumber(70u), queue.Max());
+}
+
+// Tests Contains function
+TEST_F(PacketNumberQueueTest, Contains) {
+  PacketNumberQueue queue;
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber()));
+  queue.AddRange(QuicPacketNumber(5), QuicPacketNumber(10));
+  queue.Add(QuicPacketNumber(20));
+
+  for (int i = 1; i < 5; ++i) {
+    EXPECT_FALSE(queue.Contains(QuicPacketNumber(i)));
+  }
+
+  for (int i = 5; i < 10; ++i) {
+    EXPECT_TRUE(queue.Contains(QuicPacketNumber(i)));
+  }
+  for (int i = 10; i < 20; ++i) {
+    EXPECT_FALSE(queue.Contains(QuicPacketNumber(i)));
+  }
+  EXPECT_TRUE(queue.Contains(QuicPacketNumber(20)));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(21)));
+
+  PacketNumberQueue queue2;
+  EXPECT_FALSE(queue2.Contains(QuicPacketNumber(1)));
+  for (int i = 1; i < 51; ++i) {
+    queue2.Add(QuicPacketNumber(2 * i));
+  }
+  EXPECT_FALSE(queue2.Contains(QuicPacketNumber()));
+  for (int i = 1; i < 51; ++i) {
+    if (i % 2 == 0) {
+      EXPECT_TRUE(queue2.Contains(QuicPacketNumber(i)));
+    } else {
+      EXPECT_FALSE(queue2.Contains(QuicPacketNumber(i)));
+    }
+  }
+  EXPECT_FALSE(queue2.Contains(QuicPacketNumber(101)));
+}
+
+// Tests that a queue contains the expected data after calls to RemoveUpTo().
+TEST_F(PacketNumberQueueTest, Removal) {
+  PacketNumberQueue queue;
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(51)));
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
+
+  EXPECT_TRUE(queue.RemoveUpTo(QuicPacketNumber(51)));
+  EXPECT_FALSE(queue.RemoveUpTo(QuicPacketNumber(51)));
+
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber()));
+  for (int i = 1; i < 51; ++i) {
+    EXPECT_FALSE(queue.Contains(QuicPacketNumber(i)));
+  }
+  for (int i = 51; i < 100; ++i) {
+    EXPECT_TRUE(queue.Contains(QuicPacketNumber(i)));
+  }
+  EXPECT_EQ(49u, queue.NumPacketsSlow());
+  EXPECT_EQ(QuicPacketNumber(51u), queue.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), queue.Max());
+
+  PacketNumberQueue queue2;
+  queue2.AddRange(QuicPacketNumber(1), QuicPacketNumber(5));
+  EXPECT_TRUE(queue2.RemoveUpTo(QuicPacketNumber(3)));
+  EXPECT_TRUE(queue2.RemoveUpTo(QuicPacketNumber(50)));
+  EXPECT_TRUE(queue2.Empty());
+}
+
+// Tests that a queue is empty when all of its elements are removed.
+TEST_F(PacketNumberQueueTest, Empty) {
+  PacketNumberQueue queue;
+  EXPECT_TRUE(queue.Empty());
+  EXPECT_EQ(0u, queue.NumPacketsSlow());
+
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
+  EXPECT_TRUE(queue.RemoveUpTo(QuicPacketNumber(100)));
+  EXPECT_TRUE(queue.Empty());
+  EXPECT_EQ(0u, queue.NumPacketsSlow());
+}
+
+// Tests that logging the state of a PacketNumberQueue does not crash.
+TEST_F(PacketNumberQueueTest, LogDoesNotCrash) {
+  std::ostringstream oss;
+  PacketNumberQueue queue;
+  oss << queue;
+
+  queue.Add(QuicPacketNumber(1));
+  queue.AddRange(QuicPacketNumber(50), QuicPacketNumber(100));
+  oss << queue;
+}
+
+// Tests that the iterators returned from a packet queue iterate over the queue.
+TEST_F(PacketNumberQueueTest, Iterators) {
+  PacketNumberQueue queue;
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
+
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
+      queue.begin(), queue.end());
+
+  PacketNumberQueue queue2;
+  for (int i = 1; i < 100; i++) {
+    queue2.AddRange(QuicPacketNumber(i), QuicPacketNumber(i + 1));
+  }
+
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2(
+      queue2.begin(), queue2.end());
+
+  std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(100)));
+  EXPECT_EQ(expected_intervals, actual_intervals);
+  EXPECT_EQ(expected_intervals, actual_intervals2);
+  EXPECT_EQ(actual_intervals, actual_intervals2);
+}
+
+TEST_F(PacketNumberQueueTest, ReversedIterators) {
+  PacketNumberQueue queue;
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
+  PacketNumberQueue queue2;
+  for (int i = 1; i < 100; i++) {
+    queue2.AddRange(QuicPacketNumber(i), QuicPacketNumber(i + 1));
+  }
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
+      queue.rbegin(), queue.rend());
+  const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2(
+      queue2.rbegin(), queue2.rend());
+
+  std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(100)));
+
+  EXPECT_EQ(expected_intervals, actual_intervals);
+  EXPECT_EQ(expected_intervals, actual_intervals2);
+  EXPECT_EQ(actual_intervals, actual_intervals2);
+
+  PacketNumberQueue queue3;
+  for (int i = 1; i < 20; i++) {
+    queue3.Add(QuicPacketNumber(2 * i));
+  }
+
+  auto begin = queue3.begin();
+  auto end = queue3.end();
+  --end;
+  auto rbegin = queue3.rbegin();
+  auto rend = queue3.rend();
+  --rend;
+
+  EXPECT_EQ(*begin, *rend);
+  EXPECT_EQ(*rbegin, *end);
+}
+
+TEST_F(PacketNumberQueueTest, IntervalLengthAndRemoveInterval) {
+  PacketNumberQueue queue;
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(10));
+  queue.AddRange(QuicPacketNumber(20), QuicPacketNumber(30));
+  queue.AddRange(QuicPacketNumber(40), QuicPacketNumber(50));
+  EXPECT_EQ(3u, queue.NumIntervals());
+  EXPECT_EQ(10u, queue.LastIntervalLength());
+
+  EXPECT_TRUE(queue.RemoveUpTo(QuicPacketNumber(25)));
+  EXPECT_EQ(2u, queue.NumIntervals());
+  EXPECT_EQ(10u, queue.LastIntervalLength());
+  EXPECT_EQ(QuicPacketNumber(25u), queue.Min());
+  EXPECT_EQ(QuicPacketNumber(49u), queue.Max());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace quic
diff --git a/quic/core/frames/quic_goaway_frame.cc b/quic/core/frames/quic_goaway_frame.cc
new file mode 100644
index 0000000..ff034f0
--- /dev/null
+++ b/quic/core/frames/quic_goaway_frame.cc
@@ -0,0 +1,34 @@
+// 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/frames/quic_goaway_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+
+namespace quic {
+
+QuicGoAwayFrame::QuicGoAwayFrame()
+    : control_frame_id(kInvalidControlFrameId),
+      error_code(QUIC_NO_ERROR),
+      last_good_stream_id(0) {}
+
+QuicGoAwayFrame::QuicGoAwayFrame(QuicControlFrameId control_frame_id,
+                                 QuicErrorCode error_code,
+                                 QuicStreamId last_good_stream_id,
+                                 const QuicString& reason)
+    : control_frame_id(control_frame_id),
+      error_code(error_code),
+      last_good_stream_id(last_good_stream_id),
+      reason_phrase(reason) {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicGoAwayFrame& goaway_frame) {
+  os << "{ control_frame_id: " << goaway_frame.control_frame_id
+     << ", error_code: " << goaway_frame.error_code
+     << ", last_good_stream_id: " << goaway_frame.last_good_stream_id
+     << ", reason_phrase: '" << goaway_frame.reason_phrase << "' }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_goaway_frame.h b/quic/core/frames/quic_goaway_frame.h
new file mode 100644
index 0000000..085e915
--- /dev/null
+++ b/quic/core/frames/quic_goaway_frame.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_GOAWAY_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_GOAWAY_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicGoAwayFrame {
+  QuicGoAwayFrame();
+  QuicGoAwayFrame(QuicControlFrameId control_frame_id,
+                  QuicErrorCode error_code,
+                  QuicStreamId last_good_stream_id,
+                  const QuicString& reason);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+                                                      const QuicGoAwayFrame& g);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+  QuicErrorCode error_code;
+  QuicStreamId last_good_stream_id;
+  QuicString reason_phrase;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_GOAWAY_FRAME_H_
diff --git a/quic/core/frames/quic_inlined_frame.h b/quic/core/frames/quic_inlined_frame.h
new file mode 100644
index 0000000..08c4869
--- /dev/null
+++ b/quic/core/frames/quic_inlined_frame.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2018 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_INLINED_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_INLINED_FRAME_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+// QuicInlinedFrame is the base class of all frame types that is inlined in the
+// QuicFrame class. It gurantees all inlined frame types contain a 'type' field
+// at offset 0, such that QuicFrame.type can get the correct frame type for both
+// inline and out-of-line frame types.
+template <typename DerivedT>
+struct QUIC_EXPORT_PRIVATE QuicInlinedFrame {
+  QuicInlinedFrame(QuicFrameType type) : type(type) {
+    static_assert(offsetof(DerivedT, type) == 0,
+                  "type must be the first field.");
+    static_assert(sizeof(DerivedT) <= 24,
+                  "Frames larger than 24 bytes should not be inlined.");
+  }
+  QuicFrameType type;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_INLINED_FRAME_H_
diff --git a/quic/core/frames/quic_max_stream_id_frame.cc b/quic/core/frames/quic_max_stream_id_frame.cc
new file mode 100644
index 0000000..19270e8
--- /dev/null
+++ b/quic/core/frames/quic_max_stream_id_frame.cc
@@ -0,0 +1,25 @@
+// 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/frames/quic_max_stream_id_frame.h"
+
+namespace quic {
+
+QuicMaxStreamIdFrame::QuicMaxStreamIdFrame()
+    : QuicInlinedFrame(MAX_STREAM_ID_FRAME),
+      control_frame_id(kInvalidControlFrameId) {}
+
+QuicMaxStreamIdFrame::QuicMaxStreamIdFrame(QuicControlFrameId control_frame_id,
+                                           QuicStreamId max_stream_id)
+    : QuicInlinedFrame(MAX_STREAM_ID_FRAME),
+      control_frame_id(control_frame_id),
+      max_stream_id(max_stream_id) {}
+
+std::ostream& operator<<(std::ostream& os, const QuicMaxStreamIdFrame& frame) {
+  os << "{ control_frame_id: " << frame.control_frame_id
+     << ", stream_id: " << frame.max_stream_id << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_max_stream_id_frame.h b/quic/core/frames/quic_max_stream_id_frame.h
new file mode 100644
index 0000000..6177687
--- /dev/null
+++ b/quic/core/frames/quic_max_stream_id_frame.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAM_ID_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAM_ID_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+// IETF format MAX_STREAM_ID frame.
+// This frame is used by the sender to inform the peer of the largest
+// stream id that the peer may open and that the sender will accept.
+struct QUIC_EXPORT_PRIVATE QuicMaxStreamIdFrame
+    : public QuicInlinedFrame<QuicMaxStreamIdFrame> {
+  QuicMaxStreamIdFrame();
+  QuicMaxStreamIdFrame(QuicControlFrameId control_frame_id,
+                       QuicStreamId max_stream_id);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicMaxStreamIdFrame& frame);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+
+  // The maximum stream id to support.
+  QuicStreamId max_stream_id;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAM_ID_FRAME_H_
diff --git a/quic/core/frames/quic_message_frame.cc b/quic/core/frames/quic_message_frame.cc
new file mode 100644
index 0000000..c0de272
--- /dev/null
+++ b/quic/core/frames/quic_message_frame.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2018 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/frames/quic_message_frame.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+
+namespace quic {
+
+QuicMessageFrame::QuicMessageFrame()
+    : message_id(0), data(nullptr), message_length(0) {}
+
+QuicMessageFrame::QuicMessageFrame(QuicMessageId message_id)
+    : message_id(message_id), data(nullptr), message_length(0) {}
+
+QuicMessageFrame::QuicMessageFrame(const char* data, QuicPacketLength length)
+    : message_id(0), data(data), message_length(length) {}
+
+QuicMessageFrame::~QuicMessageFrame() {}
+
+std::ostream& operator<<(std::ostream& os, const QuicMessageFrame& s) {
+  os << " message_id: " << s.message_id
+     << ", message_length: " << s.message_length << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_message_frame.h b/quic/core/frames/quic_message_frame.h
new file mode 100644
index 0000000..4accff2
--- /dev/null
+++ b/quic/core/frames/quic_message_frame.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2018 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_MESSAGE_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_MESSAGE_FRAME_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+typedef QuicInlinedVector<QuicMemSlice, 1> QuicMessageData;
+
+struct QUIC_EXPORT_PRIVATE QuicMessageFrame {
+  QuicMessageFrame();
+  explicit QuicMessageFrame(QuicMessageId message_id);
+  QuicMessageFrame(const char* data, QuicPacketLength length);
+
+  QuicMessageFrame(const QuicMessageFrame& other) = delete;
+  QuicMessageFrame& operator=(const QuicMessageFrame& other) = delete;
+
+  QuicMessageFrame(QuicMessageFrame&& other) = default;
+  QuicMessageFrame& operator=(QuicMessageFrame&& other) = default;
+
+  ~QuicMessageFrame();
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicMessageFrame& s);
+
+  // message_id is only used on the sender side and does not get serialized on
+  // wire.
+  QuicMessageId message_id;
+  // Not owned, only used on read path.
+  const char* data;
+  // Total length of message_data, must be fit into one packet.
+  QuicPacketLength message_length;
+
+  // The actual message data which is reference counted, used on write path.
+  QuicMessageData message_data;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_MESSAGE_FRAME_H_
diff --git a/quic/core/frames/quic_mtu_discovery_frame.h b/quic/core/frames/quic_mtu_discovery_frame.h
new file mode 100644
index 0000000..330df21
--- /dev/null
+++ b/quic/core/frames/quic_mtu_discovery_frame.h
@@ -0,0 +1,23 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_MTU_DISCOVERY_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_MTU_DISCOVERY_FRAME_H_
+
+#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+// A path MTU discovery frame contains no payload and is serialized as a ping
+// frame.
+struct QUIC_EXPORT_PRIVATE QuicMtuDiscoveryFrame
+    : public QuicInlinedFrame<QuicMtuDiscoveryFrame> {
+  QuicMtuDiscoveryFrame() : QuicInlinedFrame(MTU_DISCOVERY_FRAME) {}
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_MTU_DISCOVERY_FRAME_H_
diff --git a/quic/core/frames/quic_new_connection_id_frame.cc b/quic/core/frames/quic_new_connection_id_frame.cc
new file mode 100644
index 0000000..b7f63e2
--- /dev/null
+++ b/quic/core/frames/quic_new_connection_id_frame.cc
@@ -0,0 +1,33 @@
+// 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/frames/quic_new_connection_id_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+
+namespace quic {
+
+QuicNewConnectionIdFrame::QuicNewConnectionIdFrame()
+    : control_frame_id(kInvalidControlFrameId),
+      connection_id(EmptyQuicConnectionId()),
+      sequence_number(0) {}
+
+QuicNewConnectionIdFrame::QuicNewConnectionIdFrame(
+    QuicControlFrameId control_frame_id,
+    QuicConnectionId connection_id,
+    QuicConnectionIdSequenceNumber sequence_number,
+    const QuicUint128 stateless_reset_token)
+    : control_frame_id(control_frame_id),
+      connection_id(connection_id),
+      sequence_number(sequence_number),
+      stateless_reset_token(stateless_reset_token) {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicNewConnectionIdFrame& frame) {
+  os << "{ control_frame_id: " << frame.control_frame_id
+     << ", connection_id: " << frame.connection_id
+     << ", sequence_number: " << frame.sequence_number << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_new_connection_id_frame.h b/quic/core/frames/quic_new_connection_id_frame.h
new file mode 100644
index 0000000..1948d22
--- /dev/null
+++ b/quic/core/frames/quic_new_connection_id_frame.h
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_CONNECTION_ID_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_CONNECTION_ID_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicNewConnectionIdFrame {
+  QuicNewConnectionIdFrame();
+  QuicNewConnectionIdFrame(QuicControlFrameId control_frame_id,
+                           QuicConnectionId connection_id,
+                           QuicConnectionIdSequenceNumber sequence_number,
+                           const QuicUint128 stateless_reset_token);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicNewConnectionIdFrame& frame);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+  QuicConnectionId connection_id;
+  QuicConnectionIdSequenceNumber sequence_number;
+  QuicUint128 stateless_reset_token;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_CONNECTION_ID_FRAME_H_
diff --git a/quic/core/frames/quic_new_token_frame.cc b/quic/core/frames/quic_new_token_frame.cc
new file mode 100644
index 0000000..c2f4e74
--- /dev/null
+++ b/quic/core/frames/quic_new_token_frame.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2018 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/frames/quic_new_token_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+
+namespace quic {
+
+QuicNewTokenFrame::QuicNewTokenFrame()
+    : control_frame_id(kInvalidControlFrameId) {}
+
+QuicNewTokenFrame::QuicNewTokenFrame(QuicControlFrameId control_frame_id,
+                                     QuicString token)
+    : control_frame_id(control_frame_id), token(token) {}
+
+std::ostream& operator<<(std::ostream& os, const QuicNewTokenFrame& s) {
+  os << "{ control_frame_id: " << s.control_frame_id << ", token: " << s.token
+     << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_new_token_frame.h b/quic/core/frames/quic_new_token_frame.h
new file mode 100644
index 0000000..6fb0ea4
--- /dev/null
+++ b/quic/core/frames/quic_new_token_frame.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2018 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_TOKEN_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_TOKEN_FRAME_H_
+
+#include <memory>
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicNewTokenFrame {
+  QuicNewTokenFrame();
+  QuicNewTokenFrame(QuicControlFrameId control_frame_id, QuicString token);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicNewTokenFrame& s);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+
+  QuicString token;
+};
+static_assert(sizeof(QuicNewTokenFrame) <= 64,
+              "Keep the QuicNewTokenFrame size to a cacheline.");
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_TOKEN_FRAME_H_
diff --git a/quic/core/frames/quic_padding_frame.cc b/quic/core/frames/quic_padding_frame.cc
new file mode 100644
index 0000000..098a664
--- /dev/null
+++ b/quic/core/frames/quic_padding_frame.cc
@@ -0,0 +1,15 @@
+// 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/frames/quic_padding_frame.h"
+
+namespace quic {
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicPaddingFrame& padding_frame) {
+  os << "{ num_padding_bytes: " << padding_frame.num_padding_bytes << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_padding_frame.h b/quic/core/frames/quic_padding_frame.h
new file mode 100644
index 0000000..03e0a40
--- /dev/null
+++ b/quic/core/frames/quic_padding_frame.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_PADDING_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_PADDING_FRAME_H_
+
+#include <cstdint>
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+// A padding frame contains no payload.
+struct QUIC_EXPORT_PRIVATE QuicPaddingFrame
+    : public QuicInlinedFrame<QuicPaddingFrame> {
+  QuicPaddingFrame() : QuicInlinedFrame(PADDING_FRAME), num_padding_bytes(-1) {}
+  explicit QuicPaddingFrame(int num_padding_bytes)
+      : QuicInlinedFrame(PADDING_FRAME), num_padding_bytes(num_padding_bytes) {}
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicPaddingFrame& s);
+
+  // -1: full padding to the end of a max-sized packet
+  // otherwise: only pad up to num_padding_bytes bytes
+  int num_padding_bytes;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_PADDING_FRAME_H_
diff --git a/quic/core/frames/quic_path_challenge_frame.cc b/quic/core/frames/quic_path_challenge_frame.cc
new file mode 100644
index 0000000..c1ca6a8
--- /dev/null
+++ b/quic/core/frames/quic_path_challenge_frame.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2018 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/frames/quic_path_challenge_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+
+namespace quic {
+
+QuicPathChallengeFrame::QuicPathChallengeFrame()
+    : control_frame_id(kInvalidControlFrameId) {}
+
+QuicPathChallengeFrame::QuicPathChallengeFrame(
+    QuicControlFrameId control_frame_id,
+    const QuicPathFrameBuffer& data_buff)
+    : control_frame_id(control_frame_id) {
+  memcpy(data_buffer.data(), data_buff.data(), data_buffer.size());
+}
+
+QuicPathChallengeFrame::~QuicPathChallengeFrame() {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicPathChallengeFrame& frame) {
+  os << "{ control_frame_id: " << frame.control_frame_id
+     << ", data: " << static_cast<unsigned>(frame.data_buffer[0]) << " "
+     << static_cast<unsigned>(frame.data_buffer[1]) << " "
+     << static_cast<unsigned>(frame.data_buffer[2]) << " "
+     << static_cast<unsigned>(frame.data_buffer[3]) << " "
+     << static_cast<unsigned>(frame.data_buffer[4]) << " "
+     << static_cast<unsigned>(frame.data_buffer[5]) << " "
+     << static_cast<unsigned>(frame.data_buffer[6]) << " "
+     << static_cast<unsigned>(frame.data_buffer[7]) << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_path_challenge_frame.h b/quic/core/frames/quic_path_challenge_frame.h
new file mode 100644
index 0000000..46a010a
--- /dev/null
+++ b/quic/core/frames/quic_path_challenge_frame.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2018 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_CHALLENGE_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_CHALLENGE_FRAME_H_
+
+#include <memory>
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+
+namespace quic {
+
+// Size of the entire IETF Quic Path Challenge frame.
+const size_t kQuicPathChallengeFrameSize = kQuicPathFrameBufferSize;
+
+struct QUIC_EXPORT_PRIVATE QuicPathChallengeFrame {
+  QuicPathChallengeFrame();
+  QuicPathChallengeFrame(QuicControlFrameId control_frame_id,
+                         const QuicPathFrameBuffer& data_buff);
+  ~QuicPathChallengeFrame();
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicPathChallengeFrame& frame);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+
+  QuicPathFrameBuffer data_buffer;
+};
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_CHALLENGE_FRAME_H_
diff --git a/quic/core/frames/quic_path_response_frame.cc b/quic/core/frames/quic_path_response_frame.cc
new file mode 100644
index 0000000..85e9712
--- /dev/null
+++ b/quic/core/frames/quic_path_response_frame.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2018 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/frames/quic_path_response_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+
+namespace quic {
+
+QuicPathResponseFrame::QuicPathResponseFrame()
+    : control_frame_id(kInvalidControlFrameId) {}
+
+QuicPathResponseFrame::QuicPathResponseFrame(
+    QuicControlFrameId control_frame_id,
+    const QuicPathFrameBuffer& data_buff)
+    : control_frame_id(control_frame_id) {
+  memcpy(data_buffer.data(), data_buff.data(), data_buffer.size());
+}
+
+QuicPathResponseFrame::~QuicPathResponseFrame() {}
+
+std::ostream& operator<<(std::ostream& os, const QuicPathResponseFrame& frame) {
+  os << "{ control_frame_id: " << frame.control_frame_id
+     << ", data: " << static_cast<unsigned>(frame.data_buffer[0]) << " "
+     << static_cast<unsigned>(frame.data_buffer[1]) << " "
+     << static_cast<unsigned>(frame.data_buffer[2]) << " "
+     << static_cast<unsigned>(frame.data_buffer[3]) << " "
+     << static_cast<unsigned>(frame.data_buffer[4]) << " "
+     << static_cast<unsigned>(frame.data_buffer[5]) << " "
+     << static_cast<unsigned>(frame.data_buffer[6]) << " "
+     << static_cast<unsigned>(frame.data_buffer[7]) << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_path_response_frame.h b/quic/core/frames/quic_path_response_frame.h
new file mode 100644
index 0000000..e953ad8
--- /dev/null
+++ b/quic/core/frames/quic_path_response_frame.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2018 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_RESPONSE_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_RESPONSE_FRAME_H_
+
+#include <memory>
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+
+namespace quic {
+
+// Size of the entire IETF Quic Path Response frame.
+const size_t kQuicPathResponseFrameSize = kQuicPathFrameBufferSize;
+
+struct QUIC_EXPORT_PRIVATE QuicPathResponseFrame {
+  QuicPathResponseFrame();
+  QuicPathResponseFrame(QuicControlFrameId control_frame_id,
+                        const QuicPathFrameBuffer& data_buff);
+  ~QuicPathResponseFrame();
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicPathResponseFrame& frame);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+
+  QuicPathFrameBuffer data_buffer;
+};
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_RESPONSE_FRAME_H_
diff --git a/quic/core/frames/quic_ping_frame.cc b/quic/core/frames/quic_ping_frame.cc
new file mode 100644
index 0000000..d31efb0
--- /dev/null
+++ b/quic/core/frames/quic_ping_frame.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2017 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/frames/quic_ping_frame.h"
+
+namespace quic {
+
+QuicPingFrame::QuicPingFrame()
+    : QuicInlinedFrame(PING_FRAME), control_frame_id(kInvalidControlFrameId) {}
+
+QuicPingFrame::QuicPingFrame(QuicControlFrameId control_frame_id)
+    : QuicInlinedFrame(PING_FRAME), control_frame_id(control_frame_id) {}
+
+std::ostream& operator<<(std::ostream& os, const QuicPingFrame& ping_frame) {
+  os << "{ control_frame_id: " << ping_frame.control_frame_id << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_ping_frame.h b/quic/core/frames/quic_ping_frame.h
new file mode 100644
index 0000000..352d079
--- /dev/null
+++ b/quic/core/frames/quic_ping_frame.h
@@ -0,0 +1,33 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_PING_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_PING_FRAME_H_
+
+#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+// A ping frame contains no payload, though it is retransmittable,
+// and ACK'd just like other normal frames.
+struct QUIC_EXPORT_PRIVATE QuicPingFrame
+    : public QuicInlinedFrame<QuicPingFrame> {
+  QuicPingFrame();
+  explicit QuicPingFrame(QuicControlFrameId control_frame_id);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicPingFrame& ping_frame);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_PING_FRAME_H_
diff --git a/quic/core/frames/quic_retire_connection_id_frame.cc b/quic/core/frames/quic_retire_connection_id_frame.cc
new file mode 100644
index 0000000..6828ce4
--- /dev/null
+++ b/quic/core/frames/quic_retire_connection_id_frame.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2019 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/frames/quic_retire_connection_id_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+
+namespace quic {
+
+QuicRetireConnectionIdFrame::QuicRetireConnectionIdFrame()
+    : control_frame_id(kInvalidControlFrameId), sequence_number(0) {}
+
+QuicRetireConnectionIdFrame::QuicRetireConnectionIdFrame(
+    QuicControlFrameId control_frame_id,
+    QuicConnectionIdSequenceNumber sequence_number)
+    : control_frame_id(control_frame_id), sequence_number(sequence_number) {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicRetireConnectionIdFrame& frame) {
+  os << "{ control_frame_id: " << frame.control_frame_id
+     << ", sequence_number: " << frame.sequence_number << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_retire_connection_id_frame.h b/quic/core/frames/quic_retire_connection_id_frame.h
new file mode 100644
index 0000000..79521f6
--- /dev/null
+++ b/quic/core/frames/quic_retire_connection_id_frame.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2019 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_RETIRE_CONNECTION_ID_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_RETIRE_CONNECTION_ID_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicRetireConnectionIdFrame {
+  QuicRetireConnectionIdFrame();
+  QuicRetireConnectionIdFrame(QuicControlFrameId control_frame_id,
+                              QuicConnectionIdSequenceNumber sequence_number);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicRetireConnectionIdFrame& frame);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+  QuicConnectionIdSequenceNumber sequence_number;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_RETIRE_CONNECTION_ID_FRAME_H_
diff --git a/quic/core/frames/quic_rst_stream_frame.cc b/quic/core/frames/quic_rst_stream_frame.cc
new file mode 100644
index 0000000..7fbf365
--- /dev/null
+++ b/quic/core/frames/quic_rst_stream_frame.cc
@@ -0,0 +1,42 @@
+// 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/frames/quic_rst_stream_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+
+namespace quic {
+
+QuicRstStreamFrame::QuicRstStreamFrame()
+    : control_frame_id(kInvalidControlFrameId),
+      stream_id(0),
+      error_code(QUIC_STREAM_NO_ERROR),
+      byte_offset(0) {}
+
+QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id,
+                                       QuicStreamId stream_id,
+                                       QuicRstStreamErrorCode error_code,
+                                       QuicStreamOffset bytes_written)
+    : control_frame_id(control_frame_id),
+      stream_id(stream_id),
+      error_code(error_code),
+      byte_offset(bytes_written) {}
+
+QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id,
+                                       QuicStreamId stream_id,
+                                       uint16_t ietf_error_code,
+                                       QuicStreamOffset bytes_written)
+    : control_frame_id(control_frame_id),
+      stream_id(stream_id),
+      ietf_error_code(ietf_error_code),
+      byte_offset(bytes_written) {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicRstStreamFrame& rst_frame) {
+  os << "{ control_frame_id: " << rst_frame.control_frame_id
+     << ", stream_id: " << rst_frame.stream_id
+     << ", error_code: " << rst_frame.error_code << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_rst_stream_frame.h b/quic/core/frames/quic_rst_stream_frame.h
new file mode 100644
index 0000000..0957614
--- /dev/null
+++ b/quic/core/frames/quic_rst_stream_frame.h
@@ -0,0 +1,54 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_RST_STREAM_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_RST_STREAM_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicRstStreamFrame {
+  QuicRstStreamFrame();
+  QuicRstStreamFrame(QuicControlFrameId control_frame_id,
+                     QuicStreamId stream_id,
+                     QuicRstStreamErrorCode error_code,
+                     QuicStreamOffset bytes_written);
+  QuicRstStreamFrame(QuicControlFrameId control_frame_id,
+                     QuicStreamId stream_id,
+                     uint16_t ietf_error_code,
+                     QuicStreamOffset bytes_written);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicRstStreamFrame& r);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+
+  QuicStreamId stream_id;
+
+  // Caller must know whether IETF- or Google- QUIC is in use and
+  // set the appropriate error code.
+  union {
+    QuicRstStreamErrorCode error_code;
+    // In IETF QUIC the code is up to the app on top of quic, so is
+    // more general than QuicRstStreamErrorCode allows.
+    uint16_t ietf_error_code;
+  };
+
+  // Used to update flow control windows. On termination of a stream, both
+  // endpoints must inform the peer of the number of bytes they have sent on
+  // that stream. This can be done through normal termination (data packet with
+  // FIN) or through a RST.
+  QuicStreamOffset byte_offset;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_RST_STREAM_FRAME_H_
diff --git a/quic/core/frames/quic_stop_sending_frame.cc b/quic/core/frames/quic_stop_sending_frame.cc
new file mode 100644
index 0000000..1afd512
--- /dev/null
+++ b/quic/core/frames/quic_stop_sending_frame.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2018 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/frames/quic_stop_sending_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+
+namespace quic {
+
+QuicStopSendingFrame::QuicStopSendingFrame()
+    : control_frame_id(kInvalidControlFrameId),
+      stream_id(0),
+      application_error_code(0) {}
+
+QuicStopSendingFrame::QuicStopSendingFrame(
+    QuicControlFrameId control_frame_id,
+    QuicStreamId stream_id,
+    QuicApplicationErrorCode application_error_code)
+    : control_frame_id(control_frame_id),
+      stream_id(stream_id),
+      application_error_code(application_error_code) {}
+
+std::ostream& operator<<(std::ostream& os, const QuicStopSendingFrame& frame) {
+  os << "{ control_frame_id: " << frame.control_frame_id
+     << ", stream_id: " << frame.stream_id
+     << ", application_error_code: " << frame.application_error_code << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_stop_sending_frame.h b/quic/core/frames/quic_stop_sending_frame.h
new file mode 100644
index 0000000..7ca639d
--- /dev/null
+++ b/quic/core/frames/quic_stop_sending_frame.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2018 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_SENDING_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_SENDING_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame {
+  QuicStopSendingFrame();
+  QuicStopSendingFrame(QuicControlFrameId control_frame_id,
+                       QuicStreamId stream_id,
+                       QuicApplicationErrorCode application_error_code);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicStopSendingFrame& frame);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+  QuicStreamId stream_id;
+  QuicApplicationErrorCode application_error_code;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_SENDING_FRAME_H_
diff --git a/quic/core/frames/quic_stop_waiting_frame.cc b/quic/core/frames/quic_stop_waiting_frame.cc
new file mode 100644
index 0000000..02e0a62
--- /dev/null
+++ b/quic/core/frames/quic_stop_waiting_frame.cc
@@ -0,0 +1,20 @@
+// 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/frames/quic_stop_waiting_frame.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+
+namespace quic {
+
+QuicStopWaitingFrame::QuicStopWaitingFrame()
+    : QuicInlinedFrame(STOP_WAITING_FRAME) {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicStopWaitingFrame& sent_info) {
+  os << "{ least_unacked: " << sent_info.least_unacked << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_stop_waiting_frame.h b/quic/core/frames/quic_stop_waiting_frame.h
new file mode 100644
index 0000000..84bfc2a
--- /dev/null
+++ b/quic/core/frames/quic_stop_waiting_frame.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_WAITING_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_WAITING_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicStopWaitingFrame
+    : public QuicInlinedFrame<QuicStopWaitingFrame> {
+  QuicStopWaitingFrame();
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicStopWaitingFrame& s);
+
+  // The lowest packet we've sent which is unacked, and we expect an ack for.
+  QuicPacketNumber least_unacked;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_WAITING_FRAME_H_
diff --git a/quic/core/frames/quic_stream_frame.cc b/quic/core/frames/quic_stream_frame.cc
new file mode 100644
index 0000000..b9413c7
--- /dev/null
+++ b/quic/core/frames/quic_stream_frame.cc
@@ -0,0 +1,46 @@
+// 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/frames/quic_stream_frame.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+
+namespace quic {
+
+QuicStreamFrame::QuicStreamFrame()
+    : QuicStreamFrame(-1, false, 0, nullptr, 0) {}
+
+QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
+                                 bool fin,
+                                 QuicStreamOffset offset,
+                                 QuicStringPiece data)
+    : QuicStreamFrame(stream_id, fin, offset, data.data(), data.length()) {}
+
+QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
+                                 bool fin,
+                                 QuicStreamOffset offset,
+                                 QuicPacketLength data_length)
+    : QuicStreamFrame(stream_id, fin, offset, nullptr, data_length) {}
+
+QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
+                                 bool fin,
+                                 QuicStreamOffset offset,
+                                 const char* data_buffer,
+                                 QuicPacketLength data_length)
+    : QuicInlinedFrame(STREAM_FRAME),
+      fin(fin),
+      data_length(data_length),
+      stream_id(stream_id),
+      data_buffer(data_buffer),
+      offset(offset) {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicStreamFrame& stream_frame) {
+  os << "{ stream_id: " << stream_frame.stream_id
+     << ", fin: " << stream_frame.fin << ", offset: " << stream_frame.offset
+     << ", length: " << stream_frame.data_length << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_stream_frame.h b/quic/core/frames/quic_stream_frame.h
new file mode 100644
index 0000000..6cd510d
--- /dev/null
+++ b/quic/core/frames/quic_stream_frame.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_FRAME_H_
+
+#include <memory>
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+struct QUIC_EXPORT_PRIVATE QuicStreamFrame
+    : public QuicInlinedFrame<QuicStreamFrame> {
+  QuicStreamFrame();
+  QuicStreamFrame(QuicStreamId stream_id,
+                  bool fin,
+                  QuicStreamOffset offset,
+                  QuicStringPiece data);
+  QuicStreamFrame(QuicStreamId stream_id,
+                  bool fin,
+                  QuicStreamOffset offset,
+                  QuicPacketLength data_length);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+                                                      const QuicStreamFrame& s);
+
+  bool fin;
+  QuicPacketLength data_length;
+  QuicStreamId stream_id;
+  const char* data_buffer;  // Not owned.
+  QuicStreamOffset offset;  // Location of this data in the stream.
+
+  QuicStreamFrame(QuicStreamId stream_id,
+                  bool fin,
+                  QuicStreamOffset offset,
+                  const char* data_buffer,
+                  QuicPacketLength data_length);
+};
+static_assert(sizeof(QuicStreamFrame) <= 64,
+              "Keep the QuicStreamFrame size to a cacheline.");
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_FRAME_H_
diff --git a/quic/core/frames/quic_stream_id_blocked_frame.cc b/quic/core/frames/quic_stream_id_blocked_frame.cc
new file mode 100644
index 0000000..627ad2a
--- /dev/null
+++ b/quic/core/frames/quic_stream_id_blocked_frame.cc
@@ -0,0 +1,27 @@
+// 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/frames/quic_stream_id_blocked_frame.h"
+
+namespace quic {
+
+QuicStreamIdBlockedFrame::QuicStreamIdBlockedFrame()
+    : QuicInlinedFrame(STREAM_ID_BLOCKED_FRAME),
+      control_frame_id(kInvalidControlFrameId) {}
+
+QuicStreamIdBlockedFrame::QuicStreamIdBlockedFrame(
+    QuicControlFrameId control_frame_id,
+    QuicStreamId stream_id)
+    : QuicInlinedFrame(STREAM_ID_BLOCKED_FRAME),
+      control_frame_id(control_frame_id),
+      stream_id(stream_id) {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicStreamIdBlockedFrame& frame) {
+  os << "{ control_frame_id: " << frame.control_frame_id
+     << ", stream id: " << frame.stream_id << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_stream_id_blocked_frame.h b/quic/core/frames/quic_stream_id_blocked_frame.h
new file mode 100644
index 0000000..f9ccca2
--- /dev/null
+++ b/quic/core/frames/quic_stream_id_blocked_frame.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_ID_BLOCKED_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_ID_BLOCKED_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+// IETF format STREAM_ID_BLOCKED frame.
+// The sender uses this to inform the peer that the sender wished to
+// open a new stream but was blocked from doing so due due to the
+// maximum stream ID limit set by the peer (via a MAX_STREAM_ID frame)
+struct QUIC_EXPORT_PRIVATE QuicStreamIdBlockedFrame
+    : public QuicInlinedFrame<QuicStreamIdBlockedFrame> {
+  QuicStreamIdBlockedFrame();
+  QuicStreamIdBlockedFrame(QuicControlFrameId control_frame_id,
+                           QuicStreamId stream_id);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicStreamIdBlockedFrame& frame);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+
+  QuicStreamId stream_id;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_ID_BLOCKED_FRAME_H_
diff --git a/quic/core/frames/quic_window_update_frame.cc b/quic/core/frames/quic_window_update_frame.cc
new file mode 100644
index 0000000..07e3168
--- /dev/null
+++ b/quic/core/frames/quic_window_update_frame.cc
@@ -0,0 +1,29 @@
+// 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/frames/quic_window_update_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+
+namespace quic {
+
+QuicWindowUpdateFrame::QuicWindowUpdateFrame()
+    : control_frame_id(kInvalidControlFrameId) {}
+
+QuicWindowUpdateFrame::QuicWindowUpdateFrame(
+    QuicControlFrameId control_frame_id,
+    QuicStreamId stream_id,
+    QuicStreamOffset byte_offset)
+    : control_frame_id(control_frame_id),
+      stream_id(stream_id),
+      byte_offset(byte_offset) {}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicWindowUpdateFrame& window_update_frame) {
+  os << "{ control_frame_id: " << window_update_frame.control_frame_id
+     << ", stream_id: " << window_update_frame.stream_id
+     << ", byte_offset: " << window_update_frame.byte_offset << " }\n";
+  return os;
+}
+
+}  // namespace quic
diff --git a/quic/core/frames/quic_window_update_frame.h b/quic/core/frames/quic_window_update_frame.h
new file mode 100644
index 0000000..73163ce
--- /dev/null
+++ b/quic/core/frames/quic_window_update_frame.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_WINDOW_UPDATE_FRAME_H_
+#define QUICHE_QUIC_CORE_FRAMES_QUIC_WINDOW_UPDATE_FRAME_H_
+
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+
+namespace quic {
+
+// Flow control updates per-stream and at the connection level.
+// Based on SPDY's WINDOW_UPDATE frame, but uses an absolute byte offset rather
+// than a window delta.
+// TODO(rjshade): A possible future optimization is to make stream_id and
+//                byte_offset variable length, similar to stream frames.
+struct QUIC_EXPORT_PRIVATE QuicWindowUpdateFrame {
+  QuicWindowUpdateFrame();
+  QuicWindowUpdateFrame(QuicControlFrameId control_frame_id,
+                        QuicStreamId stream_id,
+                        QuicStreamOffset byte_offset);
+
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicWindowUpdateFrame& w);
+
+  // A unique identifier of this control frame. 0 when this frame is received,
+  // and non-zero when sent.
+  QuicControlFrameId control_frame_id;
+
+  // The stream this frame applies to.  0 is a special case meaning the overall
+  // connection rather than a specific stream.
+  QuicStreamId stream_id;
+
+  // Byte offset in the stream or connection. The receiver of this frame must
+  // not send data which would result in this offset being exceeded.
+  //
+  // TODO(fkastenholz): Rename this to max_data and change the type to
+  // QuicByteCount because the IETF defines this as the "maximum
+  // amount of data that can be sent".
+  QuicStreamOffset byte_offset;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_FRAMES_QUIC_WINDOW_UPDATE_FRAME_H_