Moves the remaining library targets from //third_party/spdy/core to //third_party/http2/core.

These targets are widely used in google3, so I am leaving vestigial forwarding header files and build targets, and will migrate library users via Rosie CLs.

Protected by refactoring, no functional change, not protected.

PiperOrigin-RevId: 651120420
diff --git a/build/source_list.bzl b/build/source_list.bzl
index bb7da0b..d65346b 100644
--- a/build/source_list.bzl
+++ b/build/source_list.bzl
@@ -77,13 +77,19 @@
     "http2/adapter/window_manager.h",
     "http2/core/array_output_buffer.h",
     "http2/core/header_byte_listener_interface.h",
+    "http2/core/http2_frame_decoder_adapter.h",
     "http2/core/http2_header_block_hpack_listener.h",
     "http2/core/http2_trace_logging.h",
     "http2/core/no_op_headers_handler.h",
     "http2/core/priority_write_scheduler.h",
     "http2/core/recording_headers_handler.h",
+    "http2/core/spdy_alt_svc_wire_format.h",
+    "http2/core/spdy_bitmasks.h",
+    "http2/core/spdy_frame_builder.h",
+    "http2/core/spdy_framer.h",
     "http2/core/spdy_headers_handler_interface.h",
     "http2/core/spdy_no_op_visitor.h",
+    "http2/core/spdy_protocol.h",
     "http2/core/zero_copy_output_buffer.h",
     "http2/decoder/decode_buffer.h",
     "http2/decoder/decode_http2_structures.h",
@@ -434,9 +440,14 @@
     "http2/adapter/oghttp2_util.cc",
     "http2/adapter/window_manager.cc",
     "http2/core/array_output_buffer.cc",
+    "http2/core/http2_frame_decoder_adapter.cc",
     "http2/core/http2_trace_logging.cc",
     "http2/core/recording_headers_handler.cc",
+    "http2/core/spdy_alt_svc_wire_format.cc",
+    "http2/core/spdy_frame_builder.cc",
+    "http2/core/spdy_framer.cc",
     "http2/core/spdy_no_op_visitor.cc",
+    "http2/core/spdy_protocol.cc",
     "http2/decoder/decode_buffer.cc",
     "http2/decoder/decode_http2_structures.cc",
     "http2/decoder/decode_status.cc",
@@ -688,11 +699,6 @@
     "quic/core/web_transport_write_blocked_list.cc",
     "quic/platform/api/quic_socket_address.cc",
     "spdy/core/hpack/hpack_decoder_adapter.cc",
-    "spdy/core/http2_frame_decoder_adapter.cc",
-    "spdy/core/spdy_alt_svc_wire_format.cc",
-    "spdy/core/spdy_frame_builder.cc",
-    "spdy/core/spdy_framer.cc",
-    "spdy/core/spdy_protocol.cc",
     "web_transport/complete_buffer_visitor.cc",
     "web_transport/encapsulated/encapsulated_web_transport.cc",
     "web_transport/web_transport_headers.cc",
@@ -1113,6 +1119,10 @@
     "http2/adapter/window_manager_test.cc",
     "http2/core/array_output_buffer_test.cc",
     "http2/core/priority_write_scheduler_test.cc",
+    "http2/core/spdy_alt_svc_wire_format_test.cc",
+    "http2/core/spdy_frame_builder_test.cc",
+    "http2/core/spdy_framer_test.cc",
+    "http2/core/spdy_protocol_test.cc",
     "http2/decoder/decode_buffer_test.cc",
     "http2/decoder/decode_http2_structures_test.cc",
     "http2/decoder/http2_frame_decoder_test.cc",
@@ -1326,10 +1336,6 @@
     "quic/tools/simple_ticket_crypter_test.cc",
     "spdy/core/hpack/hpack_decoder_adapter_test.cc",
     "spdy/core/hpack/hpack_round_trip_test.cc",
-    "spdy/core/spdy_alt_svc_wire_format_test.cc",
-    "spdy/core/spdy_frame_builder_test.cc",
-    "spdy/core/spdy_framer_test.cc",
-    "spdy/core/spdy_protocol_test.cc",
     "web_transport/encapsulated/encapsulated_web_transport_test.cc",
     "web_transport/web_transport_headers_test.cc",
     "web_transport/web_transport_priority_scheduler_test.cc",
diff --git a/build/source_list.gni b/build/source_list.gni
index 23aaaaa..1692b9a 100644
--- a/build/source_list.gni
+++ b/build/source_list.gni
@@ -77,13 +77,19 @@
     "src/quiche/http2/adapter/window_manager.h",
     "src/quiche/http2/core/array_output_buffer.h",
     "src/quiche/http2/core/header_byte_listener_interface.h",
+    "src/quiche/http2/core/http2_frame_decoder_adapter.h",
     "src/quiche/http2/core/http2_header_block_hpack_listener.h",
     "src/quiche/http2/core/http2_trace_logging.h",
     "src/quiche/http2/core/no_op_headers_handler.h",
     "src/quiche/http2/core/priority_write_scheduler.h",
     "src/quiche/http2/core/recording_headers_handler.h",
+    "src/quiche/http2/core/spdy_alt_svc_wire_format.h",
+    "src/quiche/http2/core/spdy_bitmasks.h",
+    "src/quiche/http2/core/spdy_frame_builder.h",
+    "src/quiche/http2/core/spdy_framer.h",
     "src/quiche/http2/core/spdy_headers_handler_interface.h",
     "src/quiche/http2/core/spdy_no_op_visitor.h",
+    "src/quiche/http2/core/spdy_protocol.h",
     "src/quiche/http2/core/zero_copy_output_buffer.h",
     "src/quiche/http2/decoder/decode_buffer.h",
     "src/quiche/http2/decoder/decode_http2_structures.h",
@@ -434,9 +440,14 @@
     "src/quiche/http2/adapter/oghttp2_util.cc",
     "src/quiche/http2/adapter/window_manager.cc",
     "src/quiche/http2/core/array_output_buffer.cc",
+    "src/quiche/http2/core/http2_frame_decoder_adapter.cc",
     "src/quiche/http2/core/http2_trace_logging.cc",
     "src/quiche/http2/core/recording_headers_handler.cc",
+    "src/quiche/http2/core/spdy_alt_svc_wire_format.cc",
+    "src/quiche/http2/core/spdy_frame_builder.cc",
+    "src/quiche/http2/core/spdy_framer.cc",
     "src/quiche/http2/core/spdy_no_op_visitor.cc",
+    "src/quiche/http2/core/spdy_protocol.cc",
     "src/quiche/http2/decoder/decode_buffer.cc",
     "src/quiche/http2/decoder/decode_http2_structures.cc",
     "src/quiche/http2/decoder/decode_status.cc",
@@ -688,11 +699,6 @@
     "src/quiche/quic/core/web_transport_write_blocked_list.cc",
     "src/quiche/quic/platform/api/quic_socket_address.cc",
     "src/quiche/spdy/core/hpack/hpack_decoder_adapter.cc",
-    "src/quiche/spdy/core/http2_frame_decoder_adapter.cc",
-    "src/quiche/spdy/core/spdy_alt_svc_wire_format.cc",
-    "src/quiche/spdy/core/spdy_frame_builder.cc",
-    "src/quiche/spdy/core/spdy_framer.cc",
-    "src/quiche/spdy/core/spdy_protocol.cc",
     "src/quiche/web_transport/complete_buffer_visitor.cc",
     "src/quiche/web_transport/encapsulated/encapsulated_web_transport.cc",
     "src/quiche/web_transport/web_transport_headers.cc",
@@ -1114,6 +1120,10 @@
     "src/quiche/http2/adapter/window_manager_test.cc",
     "src/quiche/http2/core/array_output_buffer_test.cc",
     "src/quiche/http2/core/priority_write_scheduler_test.cc",
+    "src/quiche/http2/core/spdy_alt_svc_wire_format_test.cc",
+    "src/quiche/http2/core/spdy_frame_builder_test.cc",
+    "src/quiche/http2/core/spdy_framer_test.cc",
+    "src/quiche/http2/core/spdy_protocol_test.cc",
     "src/quiche/http2/decoder/decode_buffer_test.cc",
     "src/quiche/http2/decoder/decode_http2_structures_test.cc",
     "src/quiche/http2/decoder/http2_frame_decoder_test.cc",
@@ -1327,10 +1337,6 @@
     "src/quiche/quic/tools/simple_ticket_crypter_test.cc",
     "src/quiche/spdy/core/hpack/hpack_decoder_adapter_test.cc",
     "src/quiche/spdy/core/hpack/hpack_round_trip_test.cc",
-    "src/quiche/spdy/core/spdy_alt_svc_wire_format_test.cc",
-    "src/quiche/spdy/core/spdy_frame_builder_test.cc",
-    "src/quiche/spdy/core/spdy_framer_test.cc",
-    "src/quiche/spdy/core/spdy_protocol_test.cc",
     "src/quiche/web_transport/encapsulated/encapsulated_web_transport_test.cc",
     "src/quiche/web_transport/web_transport_headers_test.cc",
     "src/quiche/web_transport/web_transport_priority_scheduler_test.cc",
diff --git a/build/source_list.json b/build/source_list.json
index 33422d0..9bb5d09 100644
--- a/build/source_list.json
+++ b/build/source_list.json
@@ -76,13 +76,19 @@
     "quiche/http2/adapter/window_manager.h",
     "quiche/http2/core/array_output_buffer.h",
     "quiche/http2/core/header_byte_listener_interface.h",
+    "quiche/http2/core/http2_frame_decoder_adapter.h",
     "quiche/http2/core/http2_header_block_hpack_listener.h",
     "quiche/http2/core/http2_trace_logging.h",
     "quiche/http2/core/no_op_headers_handler.h",
     "quiche/http2/core/priority_write_scheduler.h",
     "quiche/http2/core/recording_headers_handler.h",
+    "quiche/http2/core/spdy_alt_svc_wire_format.h",
+    "quiche/http2/core/spdy_bitmasks.h",
+    "quiche/http2/core/spdy_frame_builder.h",
+    "quiche/http2/core/spdy_framer.h",
     "quiche/http2/core/spdy_headers_handler_interface.h",
     "quiche/http2/core/spdy_no_op_visitor.h",
+    "quiche/http2/core/spdy_protocol.h",
     "quiche/http2/core/zero_copy_output_buffer.h",
     "quiche/http2/decoder/decode_buffer.h",
     "quiche/http2/decoder/decode_http2_structures.h",
@@ -433,9 +439,14 @@
     "quiche/http2/adapter/oghttp2_util.cc",
     "quiche/http2/adapter/window_manager.cc",
     "quiche/http2/core/array_output_buffer.cc",
+    "quiche/http2/core/http2_frame_decoder_adapter.cc",
     "quiche/http2/core/http2_trace_logging.cc",
     "quiche/http2/core/recording_headers_handler.cc",
+    "quiche/http2/core/spdy_alt_svc_wire_format.cc",
+    "quiche/http2/core/spdy_frame_builder.cc",
+    "quiche/http2/core/spdy_framer.cc",
     "quiche/http2/core/spdy_no_op_visitor.cc",
+    "quiche/http2/core/spdy_protocol.cc",
     "quiche/http2/decoder/decode_buffer.cc",
     "quiche/http2/decoder/decode_http2_structures.cc",
     "quiche/http2/decoder/decode_status.cc",
@@ -687,11 +698,6 @@
     "quiche/quic/core/web_transport_write_blocked_list.cc",
     "quiche/quic/platform/api/quic_socket_address.cc",
     "quiche/spdy/core/hpack/hpack_decoder_adapter.cc",
-    "quiche/spdy/core/http2_frame_decoder_adapter.cc",
-    "quiche/spdy/core/spdy_alt_svc_wire_format.cc",
-    "quiche/spdy/core/spdy_frame_builder.cc",
-    "quiche/spdy/core/spdy_framer.cc",
-    "quiche/spdy/core/spdy_protocol.cc",
     "quiche/web_transport/complete_buffer_visitor.cc",
     "quiche/web_transport/encapsulated/encapsulated_web_transport.cc",
     "quiche/web_transport/web_transport_headers.cc",
@@ -1113,6 +1119,10 @@
     "quiche/http2/adapter/window_manager_test.cc",
     "quiche/http2/core/array_output_buffer_test.cc",
     "quiche/http2/core/priority_write_scheduler_test.cc",
+    "quiche/http2/core/spdy_alt_svc_wire_format_test.cc",
+    "quiche/http2/core/spdy_frame_builder_test.cc",
+    "quiche/http2/core/spdy_framer_test.cc",
+    "quiche/http2/core/spdy_protocol_test.cc",
     "quiche/http2/decoder/decode_buffer_test.cc",
     "quiche/http2/decoder/decode_http2_structures_test.cc",
     "quiche/http2/decoder/http2_frame_decoder_test.cc",
@@ -1326,10 +1336,6 @@
     "quiche/quic/tools/simple_ticket_crypter_test.cc",
     "quiche/spdy/core/hpack/hpack_decoder_adapter_test.cc",
     "quiche/spdy/core/hpack/hpack_round_trip_test.cc",
-    "quiche/spdy/core/spdy_alt_svc_wire_format_test.cc",
-    "quiche/spdy/core/spdy_frame_builder_test.cc",
-    "quiche/spdy/core/spdy_framer_test.cc",
-    "quiche/spdy/core/spdy_protocol_test.cc",
     "quiche/web_transport/encapsulated/encapsulated_web_transport_test.cc",
     "quiche/web_transport/web_transport_headers_test.cc",
     "quiche/web_transport/web_transport_priority_scheduler_test.cc"
diff --git a/quiche/spdy/core/http2_frame_decoder_adapter.cc b/quiche/http2/core/http2_frame_decoder_adapter.cc
similarity index 99%
rename from quiche/spdy/core/http2_frame_decoder_adapter.cc
rename to quiche/http2/core/http2_frame_decoder_adapter.cc
index 8eb9370..64362d1 100644
--- a/quiche/spdy/core/http2_frame_decoder_adapter.cc
+++ b/quiche/http2/core/http2_frame_decoder_adapter.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "quiche/spdy/core/http2_frame_decoder_adapter.h"
+#include "quiche/http2/core/http2_frame_decoder_adapter.h"
 
 // Logging policy: If an error in the input is detected, QUICHE_VLOG(n) is used
 // so that the option exists to debug the situation. Otherwise, this code mostly
@@ -17,7 +17,9 @@
 #include <string>
 
 #include "absl/strings/string_view.h"
+#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
 #include "quiche/http2/core/spdy_headers_handler_interface.h"
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/http2/decoder/decode_buffer.h"
 #include "quiche/http2/decoder/decode_status.h"
 #include "quiche/http2/decoder/http2_frame_decoder.h"
@@ -29,8 +31,6 @@
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/common/quiche_endian.h"
 #include "quiche/spdy/core/hpack/hpack_decoder_adapter.h"
-#include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 using ::spdy::ExtensionVisitorInterface;
 using ::spdy::HpackDecoderAdapter;
@@ -69,7 +69,7 @@
 
 // Overwrites the fields of the header with invalid values, for the purpose
 // of identifying reading of unset fields. Only takes effect for debug builds.
-// In Address Sanatizer builds, it also marks the fields as un-readable.
+// In Address Sanitizer builds, it also marks the fields as un-readable.
 #ifndef NDEBUG
 void CorruptFrameHeader(Http2FrameHeader* header) {
   // Beyond a valid payload length, which is 2^24 - 1.
diff --git a/quiche/http2/core/http2_frame_decoder_adapter.h b/quiche/http2/core/http2_frame_decoder_adapter.h
new file mode 100644
index 0000000..2fde705
--- /dev/null
+++ b/quiche/http2/core/http2_frame_decoder_adapter.h
@@ -0,0 +1,566 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_HTTP2_CORE_HTTP2_FRAME_DECODER_ADAPTER_H_
+#define QUICHE_HTTP2_CORE_HTTP2_FRAME_DECODER_ADAPTER_H_
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <memory>
+#include <optional>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
+#include "quiche/http2/core/spdy_headers_handler_interface.h"
+#include "quiche/http2/core/spdy_protocol.h"
+#include "quiche/http2/decoder/decode_status.h"
+#include "quiche/http2/decoder/http2_frame_decoder.h"
+#include "quiche/http2/decoder/http2_frame_decoder_listener.h"
+#include "quiche/http2/http2_constants.h"
+#include "quiche/http2/http2_structures.h"
+#include "quiche/common/platform/api/quiche_export.h"
+#include "quiche/spdy/core/hpack/hpack_decoder_adapter.h"
+
+namespace spdy {
+
+class SpdyFramerVisitorInterface;
+class ExtensionVisitorInterface;
+
+}  // namespace spdy
+
+// TODO(dahollings): Perform various renames/moves suggested in cl/164660364.
+
+namespace http2 {
+
+// Adapts SpdyFramer interface to use Http2FrameDecoder.
+class QUICHE_EXPORT Http2DecoderAdapter
+    : public http2::Http2FrameDecoderListener {
+ public:
+  // HTTP2 states.
+  enum SpdyState {
+    SPDY_ERROR,
+    SPDY_READY_FOR_FRAME,  // Framer is ready for reading the next frame.
+    SPDY_FRAME_COMPLETE,  // Framer has finished reading a frame, need to reset.
+    SPDY_READING_COMMON_HEADER,
+    SPDY_CONTROL_FRAME_PAYLOAD,
+    SPDY_READ_DATA_FRAME_PADDING_LENGTH,
+    SPDY_CONSUME_PADDING,
+    SPDY_IGNORE_REMAINING_PAYLOAD,
+    SPDY_FORWARD_STREAM_FRAME,
+    SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK,
+    SPDY_CONTROL_FRAME_HEADER_BLOCK,
+    SPDY_GOAWAY_FRAME_PAYLOAD,
+    SPDY_SETTINGS_FRAME_HEADER,
+    SPDY_SETTINGS_FRAME_PAYLOAD,
+    SPDY_ALTSVC_FRAME_PAYLOAD,
+    SPDY_EXTENSION_FRAME_PAYLOAD,
+  };
+
+  // Framer error codes.
+  enum SpdyFramerError {
+    SPDY_NO_ERROR,
+    SPDY_INVALID_STREAM_ID,           // Stream ID is invalid
+    SPDY_INVALID_CONTROL_FRAME,       // Control frame is mal-formatted.
+    SPDY_CONTROL_PAYLOAD_TOO_LARGE,   // Control frame payload was too large.
+    SPDY_DECOMPRESS_FAILURE,          // There was an error decompressing.
+    SPDY_INVALID_PADDING,             // HEADERS or DATA frame padding invalid
+    SPDY_INVALID_DATA_FRAME_FLAGS,    // Data frame has invalid flags.
+    SPDY_UNEXPECTED_FRAME,            // Frame received out of order.
+    SPDY_INTERNAL_FRAMER_ERROR,       // SpdyFramer was used incorrectly.
+    SPDY_INVALID_CONTROL_FRAME_SIZE,  // Control frame not sized to spec
+    SPDY_OVERSIZED_PAYLOAD,           // Payload size was too large
+
+    // HttpDecoder or HttpDecoderAdapter error.
+    // See HpackDecodingError for description of each error code.
+    SPDY_HPACK_INDEX_VARINT_ERROR,
+    SPDY_HPACK_NAME_LENGTH_VARINT_ERROR,
+    SPDY_HPACK_VALUE_LENGTH_VARINT_ERROR,
+    SPDY_HPACK_NAME_TOO_LONG,
+    SPDY_HPACK_VALUE_TOO_LONG,
+    SPDY_HPACK_NAME_HUFFMAN_ERROR,
+    SPDY_HPACK_VALUE_HUFFMAN_ERROR,
+    SPDY_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE,
+    SPDY_HPACK_INVALID_INDEX,
+    SPDY_HPACK_INVALID_NAME_INDEX,
+    SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED,
+    SPDY_HPACK_INITIAL_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK,
+    SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING,
+    SPDY_HPACK_TRUNCATED_BLOCK,
+    SPDY_HPACK_FRAGMENT_TOO_LONG,
+    SPDY_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT,
+
+    // Set if the visitor no longer wishes to receive events for this
+    // connection.
+    SPDY_STOP_PROCESSING,
+
+    LAST_ERROR,  // Must be the last entry in the enum.
+  };
+
+  // For debugging.
+  static const char* StateToString(int state);
+  static const char* SpdyFramerErrorToString(SpdyFramerError spdy_framer_error);
+
+  Http2DecoderAdapter();
+  ~Http2DecoderAdapter() override;
+
+  Http2DecoderAdapter(const Http2DecoderAdapter&) = delete;
+  Http2DecoderAdapter& operator=(const Http2DecoderAdapter&) = delete;
+
+  // Set callbacks to be called from the framer.  A visitor must be set, or
+  // else the framer will likely crash.  It is acceptable for the visitor
+  // to do nothing.  If this is called multiple times, only the last visitor
+  // will be used.
+  void set_visitor(spdy::SpdyFramerVisitorInterface* visitor);
+  spdy::SpdyFramerVisitorInterface* visitor() const { return visitor_; }
+
+  // Set extension callbacks to be called from the framer or decoder. Optional.
+  // If called multiple times, only the last visitor will be used.
+  void set_extension_visitor(spdy::ExtensionVisitorInterface* visitor);
+  spdy::ExtensionVisitorInterface* extension_visitor() const {
+    return extension_;
+  }
+
+  // Set debug callbacks to be called from the framer. The debug visitor is
+  // completely optional and need not be set in order for normal operation.
+  // If this is called multiple times, only the last visitor will be used.
+  void set_debug_visitor(spdy::SpdyFramerDebugVisitorInterface* debug_visitor);
+  spdy::SpdyFramerDebugVisitorInterface* debug_visitor() const {
+    return debug_visitor_;
+  }
+
+  // Decode the |len| bytes of encoded HTTP/2 starting at |*data|. Returns
+  // the number of bytes consumed. It is safe to pass more bytes in than
+  // may be consumed. Should process (or otherwise buffer) as much as
+  // available.
+  //
+  // If the input contains the entirety of a DATA frame payload, GOAWAY frame
+  // Additional Debug Data field, or unknown frame payload, then the
+  // corresponding SpdyFramerVisitorInterface::OnStreamFrameData(),
+  // OnGoAwayFrameData(), or ExtensionVisitorInterface::OnFramePayload() method
+  // is guaranteed to be called exactly once, with the entire payload or field.
+  size_t ProcessInput(const char* data, size_t len);
+
+  // Current state of the decoder.
+  SpdyState state() const;
+
+  // Current error code (NO_ERROR if state != ERROR).
+  SpdyFramerError spdy_framer_error() const;
+
+  // Has any frame header looked like the start of an HTTP/1.1 (or earlier)
+  // response? Used to detect if a backend/server that we sent a request to
+  // has responded with an HTTP/1.1 (or earlier) response.
+  bool probable_http_response() const;
+
+  spdy::HpackDecoderAdapter& GetHpackDecoder() { return hpack_decoder_; }
+  const spdy::HpackDecoderAdapter& GetHpackDecoder() const {
+    return hpack_decoder_;
+  }
+
+  bool HasError() const;
+
+  // A visitor may call this method to indicate it no longer wishes to receive
+  // events for this connection.
+  void StopProcessing();
+
+  // Sets the limit on the size of received HTTP/2 frame payloads. Corresponds
+  // to SETTINGS_MAX_FRAME_SIZE as advertised to the peer.
+  void SetMaxFrameSize(size_t max_frame_size);
+
+ private:
+  bool OnFrameHeader(const Http2FrameHeader& header) override;
+  void OnDataStart(const Http2FrameHeader& header) override;
+  void OnDataPayload(const char* data, size_t len) override;
+  void OnDataEnd() override;
+  void OnHeadersStart(const Http2FrameHeader& header) override;
+  void OnHeadersPriority(const Http2PriorityFields& priority) override;
+  void OnHpackFragment(const char* data, size_t len) override;
+  void OnHeadersEnd() override;
+  void OnPriorityFrame(const Http2FrameHeader& header,
+                       const Http2PriorityFields& priority) override;
+  void OnContinuationStart(const Http2FrameHeader& header) override;
+  void OnContinuationEnd() override;
+  void OnPadLength(size_t trailing_length) override;
+  void OnPadding(const char* padding, size_t skipped_length) override;
+  void OnRstStream(const Http2FrameHeader& header,
+                   Http2ErrorCode http2_error_code) override;
+  void OnSettingsStart(const Http2FrameHeader& header) override;
+  void OnSetting(const Http2SettingFields& setting_fields) override;
+  void OnSettingsEnd() override;
+  void OnSettingsAck(const Http2FrameHeader& header) override;
+  void OnPushPromiseStart(const Http2FrameHeader& header,
+                          const Http2PushPromiseFields& promise,
+                          size_t total_padding_length) override;
+  void OnPushPromiseEnd() override;
+  void OnPing(const Http2FrameHeader& header,
+              const Http2PingFields& ping) override;
+  void OnPingAck(const Http2FrameHeader& header,
+                 const Http2PingFields& ping) override;
+  void OnGoAwayStart(const Http2FrameHeader& header,
+                     const Http2GoAwayFields& goaway) override;
+  void OnGoAwayOpaqueData(const char* data, size_t len) override;
+  void OnGoAwayEnd() override;
+  void OnWindowUpdate(const Http2FrameHeader& header,
+                      uint32_t increment) override;
+  void OnAltSvcStart(const Http2FrameHeader& header, size_t origin_length,
+                     size_t value_length) override;
+  void OnAltSvcOriginData(const char* data, size_t len) override;
+  void OnAltSvcValueData(const char* data, size_t len) override;
+  void OnAltSvcEnd() override;
+  void OnPriorityUpdateStart(
+      const Http2FrameHeader& header,
+      const Http2PriorityUpdateFields& priority_update) override;
+  void OnPriorityUpdatePayload(const char* data, size_t len) override;
+  void OnPriorityUpdateEnd() override;
+  void OnUnknownStart(const Http2FrameHeader& header) override;
+  void OnUnknownPayload(const char* data, size_t len) override;
+  void OnUnknownEnd() override;
+  void OnPaddingTooLong(const Http2FrameHeader& header,
+                        size_t missing_length) override;
+  void OnFrameSizeError(const Http2FrameHeader& header) override;
+
+  size_t ProcessInputFrame(const char* data, size_t len);
+
+  void DetermineSpdyState(DecodeStatus status);
+  void ResetBetweenFrames();
+
+  void set_spdy_state(SpdyState v);
+
+  void SetSpdyErrorAndNotify(SpdyFramerError error, std::string detailed_error);
+
+  const Http2FrameHeader& frame_header() const;
+
+  uint32_t stream_id() const;
+  Http2FrameType frame_type() const;
+
+  size_t remaining_total_payload() const;
+
+  bool IsReadingPaddingLength();
+  bool IsSkippingPadding();
+  bool IsDiscardingPayload();
+  // Called from OnXyz or OnXyzStart methods to decide whether it is OK to
+  // handle the callback.
+  bool IsOkToStartFrame(const Http2FrameHeader& header);
+  bool HasRequiredStreamId(uint32_t stream_id);
+
+  bool HasRequiredStreamId(const Http2FrameHeader& header);
+
+  bool HasRequiredStreamIdZero(uint32_t stream_id);
+
+  bool HasRequiredStreamIdZero(const Http2FrameHeader& header);
+
+  void ReportReceiveCompressedFrame(const Http2FrameHeader& header);
+
+  void CommonStartHpackBlock();
+
+  // SpdyFramer calls HandleControlFrameHeadersData even if there are zero
+  // fragment bytes in the first frame, so do the same.
+  void MaybeAnnounceEmptyFirstHpackFragment();
+  void CommonHpackFragmentEnd();
+
+  // The most recently decoded frame header; invalid after we reached the end
+  // of that frame.
+  Http2FrameHeader frame_header_;
+
+  // If decoding an HPACK block that is split across multiple frames, this holds
+  // the frame header of the HEADERS or PUSH_PROMISE that started the block.
+  Http2FrameHeader hpack_first_frame_header_;
+
+  // Amount of trailing padding. Currently used just as an indicator of whether
+  // OnPadLength has been called.
+  std::optional<size_t> opt_pad_length_;
+
+  // Temporary buffers for the AltSvc fields.
+  std::string alt_svc_origin_;
+  std::string alt_svc_value_;
+
+  // Temporary buffers for PRIORITY_UPDATE fields.
+  uint32_t prioritized_stream_id_ = 0;
+  std::string priority_field_value_;
+
+  // Listener used if we transition to an error state; the listener ignores all
+  // the callbacks.
+  Http2FrameDecoderNoOpListener no_op_listener_;
+
+  spdy::SpdyFramerVisitorInterface* visitor_ = nullptr;
+  spdy::SpdyFramerDebugVisitorInterface* debug_visitor_ = nullptr;
+
+  // If non-null, unknown frames and settings are passed to the extension.
+  spdy::ExtensionVisitorInterface* extension_ = nullptr;
+
+  // The HPACK decoder to be used for this adapter.
+  spdy::HpackDecoderAdapter hpack_decoder_;
+
+  // The HTTP/2 frame decoder.
+  Http2FrameDecoder frame_decoder_;
+
+  // Next frame type expected. Currently only used for CONTINUATION frames,
+  // but could be used for detecting whether the first frame is a SETTINGS
+  // frame.
+  // TODO(jamessynge): Provide means to indicate that decoder should require
+  // SETTINGS frame as the first frame.
+  Http2FrameType expected_frame_type_;
+
+  // Attempt to duplicate the SpdyState and SpdyFramerError values that
+  // SpdyFramer sets. Values determined by getting tests to pass.
+  SpdyState spdy_state_ = SpdyState::SPDY_READY_FOR_FRAME;
+  SpdyFramerError spdy_framer_error_ = SpdyFramerError::SPDY_NO_ERROR;
+
+  // The limit on the size of received HTTP/2 payloads as specified in the
+  // SETTINGS_MAX_FRAME_SIZE advertised to peer.
+  size_t max_frame_size_ = spdy::kHttp2DefaultFramePayloadLimit;
+
+  // Has OnFrameHeader been called?
+  bool decoded_frame_header_ = false;
+
+  // Have we recorded an Http2FrameHeader for the current frame?
+  // We only do so if the decoder will make multiple callbacks for
+  // the frame; for example, for PING frames we don't make record
+  // the frame header, but for ALTSVC we do.
+  bool has_frame_header_ = false;
+
+  // Have we recorded an Http2FrameHeader for the current HPACK block?
+  // True only for multi-frame HPACK blocks.
+  bool has_hpack_first_frame_header_ = false;
+
+  // Has OnHeaders() already been called for current HEADERS block? Only
+  // meaningful between OnHeadersStart and OnHeadersPriority.
+  bool on_headers_called_ = false;
+
+  // Has OnHpackFragment() already been called for current HPACK block?
+  // SpdyFramer will pass an empty buffer to the HPACK decoder if a HEADERS
+  // or PUSH_PROMISE has no HPACK data in it (e.g. a HEADERS frame with only
+  // padding). Detect that condition and replicate the behavior using this
+  // field.
+  bool on_hpack_fragment_called_ = false;
+
+  // Have we seen a frame header that appears to be an HTTP/1 response?
+  bool latched_probable_http_response_ = false;
+
+  // Is expected_frame_type_ set?
+  bool has_expected_frame_type_ = false;
+
+  // Is the current frame payload destined for |extension_|?
+  bool handling_extension_payload_ = false;
+};
+
+}  // namespace http2
+
+namespace spdy {
+
+// Http2DecoderAdapter will use the given visitor implementing this
+// interface to deliver event callbacks as frames are decoded.
+//
+// Control frames that contain HTTP2 header blocks (HEADER, and PUSH_PROMISE)
+// are processed in fashion that allows the decompressed header block to be
+// delivered in chunks to the visitor.
+// The following steps are followed:
+//   1. OnHeaders, or OnPushPromise is called.
+//   2. OnHeaderFrameStart is called; visitor is expected to return an instance
+//      of SpdyHeadersHandlerInterface that will receive the header key-value
+//      pairs.
+//   3. OnHeaderFrameEnd is called, indicating that the full header block has
+//      been delivered for the control frame.
+// During step 2, if the visitor is not interested in accepting the header data,
+// it should return a no-op implementation of SpdyHeadersHandlerInterface.
+class QUICHE_EXPORT SpdyFramerVisitorInterface {
+ public:
+  virtual ~SpdyFramerVisitorInterface() {}
+
+  // Called if an error is detected in the SpdyFrame protocol.
+  virtual void OnError(http2::Http2DecoderAdapter::SpdyFramerError error,
+                       std::string detailed_error) = 0;
+
+  // Called when the common header for a frame is received. Validating the
+  // common header occurs in later processing.
+  virtual void OnCommonHeader(SpdyStreamId /*stream_id*/, size_t /*length*/,
+                              uint8_t /*type*/, uint8_t /*flags*/) {}
+
+  // Called when a data frame header is received. The frame's data payload will
+  // be provided via subsequent calls to OnStreamFrameData().
+  // |stream_id| The stream receiving data.
+  // |length| The length of the payload in this DATA frame. Includes the length
+  //     of the data itself and potential padding.
+  // |fin| Whether the END_STREAM flag is set in the frame header.
+  virtual void OnDataFrameHeader(SpdyStreamId stream_id, size_t length,
+                                 bool fin) = 0;
+
+  // Called when data is received.
+  // |stream_id| The stream receiving data.
+  // |data| A buffer containing the data received.
+  // |len| The length of the data buffer.
+  virtual void OnStreamFrameData(SpdyStreamId stream_id, const char* data,
+                                 size_t len) = 0;
+
+  // Called when the other side has finished sending data on this stream.
+  // |stream_id| The stream that was receiving data.
+  virtual void OnStreamEnd(SpdyStreamId stream_id) = 0;
+
+  // Called when padding length field is received on a DATA frame.
+  // |stream_id| The stream receiving data.
+  // |value| The value of the padding length field.
+  virtual void OnStreamPadLength(SpdyStreamId /*stream_id*/, size_t /*value*/) {
+  }
+
+  // Called when padding is received (the trailing octets, not pad_len field) on
+  // a DATA frame.
+  // |stream_id| The stream receiving data.
+  // |len| The number of padding octets.
+  virtual void OnStreamPadding(SpdyStreamId stream_id, size_t len) = 0;
+
+  // Called just before processing the payload of a frame containing header
+  // data. Should return an implementation of SpdyHeadersHandlerInterface that
+  // will receive headers for stream |stream_id|. The caller will not take
+  // ownership of the headers handler. The same instance should remain live
+  // and be returned for all header frames comprising a logical header block
+  // (i.e. until OnHeaderFrameEnd() is called).
+  virtual SpdyHeadersHandlerInterface* OnHeaderFrameStart(
+      SpdyStreamId stream_id) = 0;
+
+  // Called after processing the payload of a frame containing header data.
+  virtual void OnHeaderFrameEnd(SpdyStreamId stream_id) = 0;
+
+  // Called when a RST_STREAM frame has been parsed.
+  virtual void OnRstStream(SpdyStreamId stream_id,
+                           SpdyErrorCode error_code) = 0;
+
+  // Called when a SETTINGS frame is received.
+  virtual void OnSettings() {}
+
+  // Called when a complete setting within a SETTINGS frame has been parsed.
+  // Note that |id| may or may not be a SETTINGS ID defined in the HTTP/2 spec.
+  virtual void OnSetting(SpdySettingsId id, uint32_t value) = 0;
+
+  // Called when a SETTINGS frame is received with the ACK flag set.
+  virtual void OnSettingsAck() {}
+
+  // Called before and after parsing SETTINGS id and value tuples.
+  virtual void OnSettingsEnd() = 0;
+
+  // Called when a PING frame has been parsed.
+  virtual void OnPing(SpdyPingId unique_id, bool is_ack) = 0;
+
+  // Called when a GOAWAY frame has been parsed.
+  virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
+                        SpdyErrorCode error_code) = 0;
+
+  // Called when a HEADERS frame is received.
+  // Note that header block data is not included. See OnHeaderFrameStart().
+  // |stream_id| The stream receiving the header.
+  // |payload_length| The length of the payload in this HEADERS frame. Includes
+  //     the length of the encoded header block and potential padding.
+  // |has_priority| Whether or not the headers frame included a priority value,
+  //     and stream dependency info.
+  // |weight| If |has_priority| is true, then weight (in the range [1, 256])
+  //     for the receiving stream, otherwise 0.
+  // |parent_stream_id| If |has_priority| is true the parent stream of the
+  //     receiving stream, else 0.
+  // |exclusive| If |has_priority| is true the exclusivity of dependence on the
+  //     parent stream, else false.
+  // |fin| Whether the END_STREAM flag is set in the frame header.
+  // |end| False if HEADERs frame is to be followed by a CONTINUATION frame,
+  //     or true if not.
+  virtual void OnHeaders(SpdyStreamId stream_id, size_t payload_length,
+                         bool has_priority, int weight,
+                         SpdyStreamId parent_stream_id, bool exclusive,
+                         bool fin, bool end) = 0;
+
+  // Called when a WINDOW_UPDATE frame has been parsed.
+  virtual void OnWindowUpdate(SpdyStreamId stream_id,
+                              int delta_window_size) = 0;
+
+  // Called when a goaway frame opaque data is available.
+  // |goaway_data| A buffer containing the opaque GOAWAY data chunk received.
+  // |len| The length of the header data buffer. A length of zero indicates
+  //       that the header data block has been completely sent.
+  // When this function returns true the visitor indicates that it accepted
+  // all of the data. Returning false indicates that that an error has
+  // occurred while processing the data. Default implementation returns true.
+  virtual bool OnGoAwayFrameData(const char* goaway_data, size_t len);
+
+  // Called when a PUSH_PROMISE frame is received.
+  // Note that header block data is not included. See OnHeaderFrameStart().
+  virtual void OnPushPromise(SpdyStreamId stream_id,
+                             SpdyStreamId promised_stream_id, bool end) = 0;
+
+  // Called when a CONTINUATION frame is received.
+  // Note that header block data is not included. See OnHeaderFrameStart().
+  // |stream_id| The stream receiving the CONTINUATION.
+  // |payload_length| The length of the payload in this CONTINUATION frame.
+  // |end| True if this CONTINUATION frame will not be followed by another
+  //     CONTINUATION frame.
+  virtual void OnContinuation(SpdyStreamId stream_id, size_t payload_length,
+                              bool end) = 0;
+
+  // Called when an ALTSVC frame has been parsed.
+  virtual void OnAltSvc(
+      SpdyStreamId /*stream_id*/, absl::string_view /*origin*/,
+      const SpdyAltSvcWireFormat::AlternativeServiceVector& /*altsvc_vector*/) {
+  }
+
+  // Called when a PRIORITY frame is received.
+  // |stream_id| The stream to update the priority of.
+  // |parent_stream_id| The parent stream of |stream_id|.
+  // |weight| Stream weight, in the range [1, 256].
+  // |exclusive| Whether |stream_id| should be an only child of
+  //     |parent_stream_id|.
+  virtual void OnPriority(SpdyStreamId stream_id, SpdyStreamId parent_stream_id,
+                          int weight, bool exclusive) = 0;
+
+  // Called when a PRIORITY_UPDATE frame is received on stream 0.
+  // |prioritized_stream_id| is the Prioritized Stream ID and
+  // |priority_field_value| is the Priority Field Value
+  // parsed from the frame payload.
+  virtual void OnPriorityUpdate(SpdyStreamId prioritized_stream_id,
+                                absl::string_view priority_field_value) = 0;
+
+  // Called when a frame type we don't recognize is received.
+  // Return true if this appears to be a valid extension frame, false otherwise.
+  // We distinguish between extension frames and nonsense by checking
+  // whether the stream id is valid.
+  // TODO(b/239060116): Remove this callback altogether.
+  virtual bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) = 0;
+
+  // Called when the common header for a non-standard frame is received. If the
+  // `length` is nonzero, the frame's payload will be provided via subsequent
+  // calls to OnUnknownFramePayload().
+  // |stream_id| The stream receiving the non-standard frame.
+  // |length| The length of the payload of the frame.
+  // |type| The type of the frame. This type is non-standard.
+  // |flags| The flags of the frame.
+  virtual void OnUnknownFrameStart(SpdyStreamId stream_id, size_t length,
+                                   uint8_t type, uint8_t flags) = 0;
+
+  // Called when a non-empty payload chunk for a non-standard frame is received.
+  // The payload for a single frame may be delivered as multiple calls to
+  // OnUnknownFramePayload(). Since the length field is passed in
+  // OnUnknownFrameStart(), there is no explicit indication of the end of the
+  // frame payload.
+  // |stream_id| The stream receiving the non-standard frame.
+  // |payload| The payload chunk, which will be non-empty.
+  virtual void OnUnknownFramePayload(SpdyStreamId stream_id,
+                                     absl::string_view payload) = 0;
+};
+
+class QUICHE_EXPORT ExtensionVisitorInterface {
+ public:
+  virtual ~ExtensionVisitorInterface() {}
+
+  // Called when non-standard SETTINGS are received.
+  virtual void OnSetting(SpdySettingsId id, uint32_t value) = 0;
+
+  // Called when non-standard frames are received.
+  virtual bool OnFrameHeader(SpdyStreamId stream_id, size_t length,
+                             uint8_t type, uint8_t flags) = 0;
+
+  // The payload for a single frame may be delivered as multiple calls to
+  // OnFramePayload. Since the length field is passed in OnFrameHeader, there is
+  // no explicit indication of the end of the frame payload.
+  virtual void OnFramePayload(const char* data, size_t len) = 0;
+};
+
+}  // namespace spdy
+
+#endif  // QUICHE_HTTP2_CORE_HTTP2_FRAME_DECODER_ADAPTER_H_
diff --git a/quiche/http2/core/http2_trace_logging.cc b/quiche/http2/core/http2_trace_logging.cc
index 30988a9..7ae1fa1 100644
--- a/quiche/http2/core/http2_trace_logging.cc
+++ b/quiche/http2/core/http2_trace_logging.cc
@@ -8,11 +8,11 @@
 
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/common/platform/api/quiche_bug_tracker.h"
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/common/quiche_callbacks.h"
 #include "quiche/spdy/core/http2_header_block.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 // Convenience macros for printing function arguments in log lines in the
 // format arg_name=value.
diff --git a/quiche/http2/core/http2_trace_logging.h b/quiche/http2/core/http2_trace_logging.h
index 84f7898..1d11ac3 100644
--- a/quiche/http2/core/http2_trace_logging.h
+++ b/quiche/http2/core/http2_trace_logging.h
@@ -8,13 +8,13 @@
 #include <cstdint>
 
 #include "absl/strings/string_view.h"
+#include "quiche/http2/core/http2_frame_decoder_adapter.h"
 #include "quiche/http2/core/recording_headers_handler.h"
 #include "quiche/http2/core/spdy_headers_handler_interface.h"
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/common/platform/api/quiche_export.h"
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/common/quiche_callbacks.h"
-#include "quiche/spdy/core/http2_frame_decoder_adapter.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 // Logging macro to use for all HTTP/2 trace logging. Iff trace logging is
 // enabled, logs at level INFO with a common prefix prepended (to facilitate
diff --git a/quiche/http2/core/priority_write_scheduler.h b/quiche/http2/core/priority_write_scheduler.h
index 0e33111..7cab893 100644
--- a/quiche/http2/core/priority_write_scheduler.h
+++ b/quiche/http2/core/priority_write_scheduler.h
@@ -18,11 +18,11 @@
 #include "absl/container/flat_hash_map.h"
 #include "absl/strings/str_cat.h"
 #include "absl/time/time.h"
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/common/platform/api/quiche_bug_tracker.h"
 #include "quiche/common/platform/api/quiche_export.h"
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/common/quiche_circular_deque.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 namespace http2 {
 
diff --git a/quiche/http2/core/priority_write_scheduler_test.cc b/quiche/http2/core/priority_write_scheduler_test.cc
index 4ac72bc..e290c42 100644
--- a/quiche/http2/core/priority_write_scheduler_test.cc
+++ b/quiche/http2/core/priority_write_scheduler_test.cc
@@ -4,15 +4,14 @@
 
 #include "quiche/http2/core/priority_write_scheduler.h"
 
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/http2/test_tools/spdy_test_utils.h"
 #include "quiche/common/platform/api/quiche_expect_bug.h"
 #include "quiche/common/platform/api/quiche_test.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 namespace http2 {
 namespace test {
 
-using ::spdy::kHttp2RootStreamId;
 using ::spdy::SpdyPriority;
 using ::spdy::SpdyStreamId;
 using ::testing::Eq;
diff --git a/quiche/spdy/core/spdy_alt_svc_wire_format.cc b/quiche/http2/core/spdy_alt_svc_wire_format.cc
similarity index 99%
rename from quiche/spdy/core/spdy_alt_svc_wire_format.cc
rename to quiche/http2/core/spdy_alt_svc_wire_format.cc
index 7981975..422e1ab 100644
--- a/quiche/spdy/core/spdy_alt_svc_wire_format.cc
+++ b/quiche/http2/core/spdy_alt_svc_wire_format.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
+#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
 
 #include <algorithm>
 #include <cctype>
diff --git a/quiche/http2/core/spdy_alt_svc_wire_format.h b/quiche/http2/core/spdy_alt_svc_wire_format.h
new file mode 100644
index 0000000..3d57b50
--- /dev/null
+++ b/quiche/http2/core/spdy_alt_svc_wire_format.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2015 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.
+
+// This file contains data structures and utility functions used for serializing
+// and parsing alternative service header values, common to HTTP/1.1 header
+// fields and HTTP/2 and QUIC ALTSVC frames.  See specification at
+// https://httpwg.github.io/http-extensions/alt-svc.html.
+
+#ifndef QUICHE_HTTP2_CORE_SPDY_ALT_SVC_WIRE_FORMAT_H_
+#define QUICHE_HTTP2_CORE_SPDY_ALT_SVC_WIRE_FORMAT_H_
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/string_view.h"
+#include "quiche/common/platform/api/quiche_export.h"
+
+namespace spdy {
+
+namespace test {
+class SpdyAltSvcWireFormatPeer;
+}  // namespace test
+
+class QUICHE_EXPORT SpdyAltSvcWireFormat {
+ public:
+  using VersionVector = absl::InlinedVector<uint32_t, 8>;
+
+  struct QUICHE_EXPORT AlternativeService {
+    std::string protocol_id;
+    std::string host;
+
+    // Default is 0: invalid port.
+    uint16_t port = 0;
+    // Default is one day.
+    uint32_t max_age_seconds = 86400;
+    // Default is empty: unspecified version.
+    VersionVector version;
+
+    AlternativeService();
+    AlternativeService(const std::string& protocol_id, const std::string& host,
+                       uint16_t port, uint32_t max_age_seconds,
+                       VersionVector version);
+    AlternativeService(const AlternativeService& other);
+    ~AlternativeService();
+
+    bool operator==(const AlternativeService& other) const {
+      return protocol_id == other.protocol_id && host == other.host &&
+             port == other.port && version == other.version &&
+             max_age_seconds == other.max_age_seconds;
+    }
+  };
+  // An empty vector means alternative services should be cleared for given
+  // origin.  Note that the wire format for this is the string "clear", not an
+  // empty value (which is invalid).
+  typedef std::vector<AlternativeService> AlternativeServiceVector;
+
+  friend class test::SpdyAltSvcWireFormatPeer;
+  static bool ParseHeaderFieldValue(absl::string_view value,
+                                    AlternativeServiceVector* altsvc_vector);
+  static std::string SerializeHeaderFieldValue(
+      const AlternativeServiceVector& altsvc_vector);
+
+ private:
+  // Forward |*c| over space and tab or until |end| is reached.
+  static void SkipWhiteSpace(absl::string_view::const_iterator* c,
+                             absl::string_view::const_iterator end);
+  // Decode percent-decoded string between |c| and |end| into |*output|.
+  // Return true on success, false if input is invalid.
+  static bool PercentDecode(absl::string_view::const_iterator c,
+                            absl::string_view::const_iterator end,
+                            std::string* output);
+  // Parse the authority part of Alt-Svc between |c| and |end| into |*host| and
+  // |*port|.  Return true on success, false if input is invalid.
+  static bool ParseAltAuthority(absl::string_view::const_iterator c,
+                                absl::string_view::const_iterator end,
+                                std::string* host, uint16_t* port);
+  // Parse a positive integer between |c| and |end| into |*value|.
+  // Return true on success, false if input is not a positive integer or it
+  // cannot be represented on uint16_t.
+  static bool ParsePositiveInteger16(absl::string_view::const_iterator c,
+                                     absl::string_view::const_iterator end,
+                                     uint16_t* value);
+  // Parse a positive integer between |c| and |end| into |*value|.
+  // Return true on success, false if input is not a positive integer or it
+  // cannot be represented on uint32_t.
+  static bool ParsePositiveInteger32(absl::string_view::const_iterator c,
+                                     absl::string_view::const_iterator end,
+                                     uint32_t* value);
+  // Parse |c| as hexadecimal digit, case insensitive.  |c| must be [0-9a-fA-F].
+  // Output is between 0 and 15.
+  static char HexDigitToInt(char c);
+  // Parse |data| as hexadecimal number into |*value|.  |data| must only contain
+  // hexadecimal digits, no "0x" prefix.
+  // Return true on success, false if input is empty, not valid hexadecimal
+  // number, or cannot be represented on uint32_t.
+  static bool HexDecodeToUInt32(absl::string_view data, uint32_t* value);
+};
+
+}  // namespace spdy
+
+#endif  // QUICHE_HTTP2_CORE_SPDY_ALT_SVC_WIRE_FORMAT_H_
diff --git a/quiche/spdy/core/spdy_alt_svc_wire_format_test.cc b/quiche/http2/core/spdy_alt_svc_wire_format_test.cc
similarity index 99%
rename from quiche/spdy/core/spdy_alt_svc_wire_format_test.cc
rename to quiche/http2/core/spdy_alt_svc_wire_format_test.cc
index 0b1b2e6..fc57dc2 100644
--- a/quiche/spdy/core/spdy_alt_svc_wire_format_test.cc
+++ b/quiche/http2/core/spdy_alt_svc_wire_format_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
+#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
 
 #include <cstddef>
 #include <cstdint>
diff --git a/quiche/http2/core/spdy_bitmasks.h b/quiche/http2/core/spdy_bitmasks.h
new file mode 100644
index 0000000..8da227c
--- /dev/null
+++ b/quiche/http2/core/spdy_bitmasks.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_HTTP2_CORE_SPDY_BITMASKS_H_
+#define QUICHE_HTTP2_CORE_SPDY_BITMASKS_H_
+
+namespace spdy {
+
+// StreamId mask from the SpdyHeader
+inline constexpr unsigned int kStreamIdMask = 0x7fffffff;
+
+// Mask the lower 24 bits.
+inline constexpr unsigned int kLengthMask = 0xffffff;
+
+}  // namespace spdy
+
+#endif  // QUICHE_HTTP2_CORE_SPDY_BITMASKS_H_
diff --git a/quiche/spdy/core/spdy_frame_builder.cc b/quiche/http2/core/spdy_frame_builder.cc
similarity index 97%
rename from quiche/spdy/core/spdy_frame_builder.cc
rename to quiche/http2/core/spdy_frame_builder.cc
index 783fd03..cec9f4d 100644
--- a/quiche/spdy/core/spdy_frame_builder.cc
+++ b/quiche/http2/core/spdy_frame_builder.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "quiche/spdy/core/spdy_frame_builder.h"
+#include "quiche/http2/core/spdy_frame_builder.h"
 
 #include <algorithm>
 #include <cstddef>
@@ -10,11 +10,11 @@
 #include <cstring>
 
 #include "absl/strings/string_view.h"
+#include "quiche/http2/core/spdy_bitmasks.h"
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/http2/core/zero_copy_output_buffer.h"
 #include "quiche/common/platform/api/quiche_bug_tracker.h"
 #include "quiche/common/platform/api/quiche_logging.h"
-#include "quiche/spdy/core/spdy_bitmasks.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 namespace spdy {
 
diff --git a/quiche/http2/core/spdy_frame_builder.h b/quiche/http2/core/spdy_frame_builder.h
new file mode 100644
index 0000000..ee879a4
--- /dev/null
+++ b/quiche/http2/core/spdy_frame_builder.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_HTTP2_CORE_SPDY_FRAME_BUILDER_H_
+#define QUICHE_HTTP2_CORE_SPDY_FRAME_BUILDER_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+
+#include "absl/strings/string_view.h"
+#include "quiche/http2/core/spdy_protocol.h"
+#include "quiche/http2/core/zero_copy_output_buffer.h"
+#include "quiche/common/platform/api/quiche_bug_tracker.h"
+#include "quiche/common/platform/api/quiche_export.h"
+#include "quiche/common/quiche_endian.h"
+
+namespace spdy {
+
+namespace test {
+class SpdyFrameBuilderPeer;
+}  // namespace test
+
+// This class provides facilities for basic binary value packing
+// into Spdy frames.
+//
+// The SpdyFrameBuilder supports appending primitive values (int, string, etc)
+// to a frame instance.  The SpdyFrameBuilder grows its internal memory buffer
+// dynamically to hold the sequence of primitive values.   The internal memory
+// buffer is exposed as the "data" of the SpdyFrameBuilder.
+class QUICHE_EXPORT SpdyFrameBuilder {
+ public:
+  // Initializes a SpdyFrameBuilder with a buffer of given size
+  explicit SpdyFrameBuilder(size_t size);
+  // Doesn't take ownership of output.
+  SpdyFrameBuilder(size_t size, ZeroCopyOutputBuffer* output);
+
+  ~SpdyFrameBuilder();
+
+  // Returns the total size of the SpdyFrameBuilder's data, which may include
+  // multiple frames.
+  size_t length() const { return offset_ + length_; }
+
+  // Seeks forward by the given number of bytes. Useful in conjunction with
+  // GetWriteableBuffer() above.
+  bool Seek(size_t length);
+
+  // Populates this frame with a HTTP2 frame prefix using length information
+  // from |capacity_|. The given type must be a control frame type.
+  bool BeginNewFrame(SpdyFrameType type, uint8_t flags, SpdyStreamId stream_id);
+
+  // Populates this frame with a HTTP2 frame prefix with type and length
+  // information.  |type| must be a defined frame type.
+  bool BeginNewFrame(SpdyFrameType type, uint8_t flags, SpdyStreamId stream_id,
+                     size_t length);
+
+  // Populates this frame with a HTTP2 frame prefix with type and length
+  // information.  |raw_frame_type| may be a defined or undefined frame type.
+  bool BeginNewUncheckedFrame(uint8_t raw_frame_type, uint8_t flags,
+                              SpdyStreamId stream_id, size_t length);
+
+  // Takes the buffer from the SpdyFrameBuilder.
+  SpdySerializedFrame take() {
+    QUICHE_BUG_IF(spdy_bug_39_1, output_ != nullptr)
+        << "ZeroCopyOutputBuffer is used to build "
+        << "frames. take() shouldn't be called";
+    QUICHE_BUG_IF(spdy_bug_39_2, kMaxFrameSizeLimit < length_)
+        << "Frame length " << length_
+        << " is longer than the maximum possible allowed length.";
+    SpdySerializedFrame rv(std::move(buffer_), length());
+    capacity_ = 0;
+    length_ = 0;
+    offset_ = 0;
+    return rv;
+  }
+
+  // Methods for adding to the payload.  These values are appended to the end
+  // of the SpdyFrameBuilder payload. Note - binary integers are converted from
+  // host to network form.
+  bool WriteUInt8(uint8_t value) { return WriteBytes(&value, sizeof(value)); }
+  bool WriteUInt16(uint16_t value) {
+    value = quiche::QuicheEndian::HostToNet16(value);
+    return WriteBytes(&value, sizeof(value));
+  }
+  bool WriteUInt24(uint32_t value) {
+    value = quiche::QuicheEndian::HostToNet32(value);
+    return WriteBytes(reinterpret_cast<char*>(&value) + 1, sizeof(value) - 1);
+  }
+  bool WriteUInt32(uint32_t value) {
+    value = quiche::QuicheEndian::HostToNet32(value);
+    return WriteBytes(&value, sizeof(value));
+  }
+  bool WriteUInt64(uint64_t value) {
+    uint32_t upper =
+        quiche::QuicheEndian::HostToNet32(static_cast<uint32_t>(value >> 32));
+    uint32_t lower =
+        quiche::QuicheEndian::HostToNet32(static_cast<uint32_t>(value));
+    return (WriteBytes(&upper, sizeof(upper)) &&
+            WriteBytes(&lower, sizeof(lower)));
+  }
+  bool WriteStringPiece32(const absl::string_view value);
+  bool WriteBytes(const void* data, uint32_t data_len);
+
+ private:
+  friend class test::SpdyFrameBuilderPeer;
+
+  // Populates this frame with a HTTP2 frame prefix with type and length
+  // information.
+  bool BeginNewFrameInternal(uint8_t raw_frame_type, uint8_t flags,
+                             SpdyStreamId stream_id, size_t length);
+
+  // Returns a writeable buffer of given size in bytes, to be appended to the
+  // currently written frame. Does bounds checking on length but does not
+  // increment the underlying iterator. To do so, consumers should subsequently
+  // call Seek().
+  // In general, consumers should use Write*() calls instead of this.
+  // Returns NULL on failure.
+  char* GetWritableBuffer(size_t length);
+  char* GetWritableOutput(size_t desired_length, size_t* actual_length);
+
+  // Checks to make sure that there is an appropriate amount of space for a
+  // write of given size, in bytes.
+  bool CanWrite(size_t length) const;
+
+  // A buffer to be created whenever a new frame needs to be written. Used only
+  // if |output_| is nullptr.
+  std::unique_ptr<char[]> buffer_;
+  // A pre-allocated buffer. If not-null, serialized frame data is written to
+  // this buffer.
+  ZeroCopyOutputBuffer* output_ = nullptr;  // Does not own.
+
+  size_t capacity_;  // Allocation size of payload, set by constructor.
+  size_t length_;    // Length of the latest frame in the buffer.
+  size_t offset_;    // Position at which the latest frame begins.
+};
+
+}  // namespace spdy
+
+#endif  // QUICHE_HTTP2_CORE_SPDY_FRAME_BUILDER_H_
diff --git a/quiche/spdy/core/spdy_frame_builder_test.cc b/quiche/http2/core/spdy_frame_builder_test.cc
similarity index 96%
rename from quiche/spdy/core/spdy_frame_builder_test.cc
rename to quiche/http2/core/spdy_frame_builder_test.cc
index 4992ead..3fe48ca 100644
--- a/quiche/spdy/core/spdy_frame_builder_test.cc
+++ b/quiche/http2/core/spdy_frame_builder_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "quiche/spdy/core/spdy_frame_builder.h"
+#include "quiche/http2/core/spdy_frame_builder.h"
 
 #include <cstddef>
 #include <cstdint>
@@ -10,10 +10,10 @@
 
 #include "absl/strings/string_view.h"
 #include "quiche/http2/core/array_output_buffer.h"
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/http2/test_tools/spdy_test_utils.h"
 #include "quiche/common/platform/api/quiche_export.h"
 #include "quiche/common/platform/api/quiche_test.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 namespace spdy {
 
diff --git a/quiche/spdy/core/spdy_framer.cc b/quiche/http2/core/spdy_framer.cc
similarity index 99%
rename from quiche/spdy/core/spdy_framer.cc
rename to quiche/http2/core/spdy_framer.cc
index 2e30a95..3539082 100644
--- a/quiche/spdy/core/spdy_framer.cc
+++ b/quiche/http2/core/spdy_framer.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "quiche/spdy/core/spdy_framer.h"
+#include "quiche/http2/core/spdy_framer.h"
 
 #include <algorithm>
 #include <cstddef>
@@ -13,15 +13,15 @@
 
 #include "absl/base/attributes.h"
 #include "absl/memory/memory.h"
+#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
+#include "quiche/http2/core/spdy_frame_builder.h"
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/http2/core/zero_copy_output_buffer.h"
 #include "quiche/http2/hpack/hpack_constants.h"
 #include "quiche/http2/hpack/hpack_encoder.h"
 #include "quiche/common/platform/api/quiche_bug_tracker.h"
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/spdy/core/http2_header_block.h"
-#include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
-#include "quiche/spdy/core/spdy_frame_builder.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 namespace spdy {
 
diff --git a/quiche/http2/core/spdy_framer.h b/quiche/http2/core/spdy_framer.h
new file mode 100644
index 0000000..b656893
--- /dev/null
+++ b/quiche/http2/core/spdy_framer.h
@@ -0,0 +1,371 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_HTTP2_CORE_SPDY_FRAMER_H_
+#define QUICHE_HTTP2_CORE_SPDY_FRAMER_H_
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "quiche/http2/core/spdy_protocol.h"
+#include "quiche/http2/core/zero_copy_output_buffer.h"
+#include "quiche/http2/hpack/hpack_encoder.h"
+#include "quiche/common/platform/api/quiche_export.h"
+
+namespace spdy {
+
+namespace test {
+
+class SpdyFramerPeer;
+class SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
+class SpdyFramerTest_PushPromiseFramesWithIterator_Test;
+
+}  // namespace test
+
+class QUICHE_EXPORT SpdyFrameSequence {
+ public:
+  virtual ~SpdyFrameSequence() {}
+
+  // Serializes the next frame in the sequence to |output|. Returns the number
+  // of bytes written to |output|.
+  virtual size_t NextFrame(ZeroCopyOutputBuffer* output) = 0;
+
+  // Returns true iff there is at least one more frame in the sequence.
+  virtual bool HasNextFrame() const = 0;
+
+  // Get SpdyFrameIR of the frame to be serialized.
+  virtual const SpdyFrameIR& GetIR() const = 0;
+};
+
+class QUICHE_EXPORT SpdyFramer {
+ public:
+  enum CompressionOption {
+    ENABLE_COMPRESSION,
+    DISABLE_COMPRESSION,
+  };
+
+  // Create a SpdyFrameSequence to serialize |frame_ir|.
+  static std::unique_ptr<SpdyFrameSequence> CreateIterator(
+      SpdyFramer* framer, std::unique_ptr<const SpdyFrameIR> frame_ir);
+
+  // Gets the serialized flags for the given |frame|.
+  static uint8_t GetSerializedFlags(const SpdyFrameIR& frame);
+
+  // Serialize a data frame.
+  static SpdySerializedFrame SerializeData(const SpdyDataIR& data_ir);
+  // Serializes the data frame header and optionally padding length fields,
+  // excluding actual data payload and padding.
+  static SpdySerializedFrame SerializeDataFrameHeaderWithPaddingLengthField(
+      const SpdyDataIR& data_ir);
+
+  // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE
+  // frame is used to implement per stream flow control.
+  static SpdySerializedFrame SerializeWindowUpdate(
+      const SpdyWindowUpdateIR& window_update);
+
+  explicit SpdyFramer(CompressionOption option);
+
+  virtual ~SpdyFramer();
+
+  // Set debug callbacks to be called from the framer. The debug visitor is
+  // completely optional and need not be set in order for normal operation.
+  // If this is called multiple times, only the last visitor will be used.
+  void set_debug_visitor(SpdyFramerDebugVisitorInterface* debug_visitor);
+
+  SpdySerializedFrame SerializeRstStream(
+      const SpdyRstStreamIR& rst_stream) const;
+
+  // Serializes a SETTINGS frame. The SETTINGS frame is
+  // used to communicate name/value pairs relevant to the communication channel.
+  SpdySerializedFrame SerializeSettings(const SpdySettingsIR& settings) const;
+
+  // Serializes a PING frame. The unique_id is used to
+  // identify the ping request/response.
+  SpdySerializedFrame SerializePing(const SpdyPingIR& ping) const;
+
+  // Serializes a GOAWAY frame. The GOAWAY frame is used
+  // prior to the shutting down of the TCP connection, and includes the
+  // stream_id of the last stream the sender of the frame is willing to process
+  // to completion.
+  SpdySerializedFrame SerializeGoAway(const SpdyGoAwayIR& goaway) const;
+
+  // Serializes a HEADERS frame. The HEADERS frame is used
+  // for sending headers.
+  SpdySerializedFrame SerializeHeaders(const SpdyHeadersIR& headers);
+
+  // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used
+  // to inform the client that it will be receiving an additional stream
+  // in response to the original request. The frame includes synthesized
+  // headers to explain the upcoming data.
+  SpdySerializedFrame SerializePushPromise(
+      const SpdyPushPromiseIR& push_promise);
+
+  // Serializes a CONTINUATION frame. The CONTINUATION frame is used
+  // to continue a sequence of header block fragments.
+  SpdySerializedFrame SerializeContinuation(
+      const SpdyContinuationIR& continuation) const;
+
+  // Serializes an ALTSVC frame. The ALTSVC frame advertises the
+  // availability of an alternative service to the client.
+  SpdySerializedFrame SerializeAltSvc(const SpdyAltSvcIR& altsvc);
+
+  // Serializes a PRIORITY frame. The PRIORITY frame advises a change in
+  // the relative priority of the given stream.
+  SpdySerializedFrame SerializePriority(const SpdyPriorityIR& priority) const;
+
+  // Serializes a PRIORITY_UPDATE frame.
+  // See https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html.
+  SpdySerializedFrame SerializePriorityUpdate(
+      const SpdyPriorityUpdateIR& priority_update) const;
+
+  // Serializes an ACCEPT_CH frame.  See
+  // https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02.
+  SpdySerializedFrame SerializeAcceptCh(const SpdyAcceptChIR& accept_ch) const;
+
+  // Serializes an unknown frame given a frame header and payload.
+  SpdySerializedFrame SerializeUnknown(const SpdyUnknownIR& unknown) const;
+
+  // Serialize a frame of unknown type.
+  SpdySerializedFrame SerializeFrame(const SpdyFrameIR& frame);
+
+  // Serialize a data frame.
+  bool SerializeData(const SpdyDataIR& data,
+                     ZeroCopyOutputBuffer* output) const;
+
+  // Serializes the data frame header and optionally padding length fields,
+  // excluding actual data payload and padding.
+  bool SerializeDataFrameHeaderWithPaddingLengthField(
+      const SpdyDataIR& data, ZeroCopyOutputBuffer* output) const;
+
+  bool SerializeRstStream(const SpdyRstStreamIR& rst_stream,
+                          ZeroCopyOutputBuffer* output) const;
+
+  // Serializes a SETTINGS frame. The SETTINGS frame is
+  // used to communicate name/value pairs relevant to the communication channel.
+  bool SerializeSettings(const SpdySettingsIR& settings,
+                         ZeroCopyOutputBuffer* output) const;
+
+  // Serializes a PING frame. The unique_id is used to
+  // identify the ping request/response.
+  bool SerializePing(const SpdyPingIR& ping,
+                     ZeroCopyOutputBuffer* output) const;
+
+  // Serializes a GOAWAY frame. The GOAWAY frame is used
+  // prior to the shutting down of the TCP connection, and includes the
+  // stream_id of the last stream the sender of the frame is willing to process
+  // to completion.
+  bool SerializeGoAway(const SpdyGoAwayIR& goaway,
+                       ZeroCopyOutputBuffer* output) const;
+
+  // Serializes a HEADERS frame. The HEADERS frame is used
+  // for sending headers.
+  bool SerializeHeaders(const SpdyHeadersIR& headers,
+                        ZeroCopyOutputBuffer* output);
+
+  // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE
+  // frame is used to implement per stream flow control.
+  bool SerializeWindowUpdate(const SpdyWindowUpdateIR& window_update,
+                             ZeroCopyOutputBuffer* output) const;
+
+  // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used
+  // to inform the client that it will be receiving an additional stream
+  // in response to the original request. The frame includes synthesized
+  // headers to explain the upcoming data.
+  bool SerializePushPromise(const SpdyPushPromiseIR& push_promise,
+                            ZeroCopyOutputBuffer* output);
+
+  // Serializes a CONTINUATION frame. The CONTINUATION frame is used
+  // to continue a sequence of header block fragments.
+  bool SerializeContinuation(const SpdyContinuationIR& continuation,
+                             ZeroCopyOutputBuffer* output) const;
+
+  // Serializes an ALTSVC frame. The ALTSVC frame advertises the
+  // availability of an alternative service to the client.
+  bool SerializeAltSvc(const SpdyAltSvcIR& altsvc,
+                       ZeroCopyOutputBuffer* output);
+
+  // Serializes a PRIORITY frame. The PRIORITY frame advises a change in
+  // the relative priority of the given stream.
+  bool SerializePriority(const SpdyPriorityIR& priority,
+                         ZeroCopyOutputBuffer* output) const;
+
+  // Serializes a PRIORITY_UPDATE frame.
+  // See https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html.
+  bool SerializePriorityUpdate(const SpdyPriorityUpdateIR& priority_update,
+                               ZeroCopyOutputBuffer* output) const;
+
+  // Serializes an ACCEPT_CH frame.  See
+  // https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02.
+  bool SerializeAcceptCh(const SpdyAcceptChIR& accept_ch,
+                         ZeroCopyOutputBuffer* output) const;
+
+  // Serializes an unknown frame given a frame header and payload.
+  bool SerializeUnknown(const SpdyUnknownIR& unknown,
+                        ZeroCopyOutputBuffer* output) const;
+
+  // Serialize a frame of unknown type.
+  size_t SerializeFrame(const SpdyFrameIR& frame, ZeroCopyOutputBuffer* output);
+
+  // Returns whether this SpdyFramer will compress header blocks using HPACK.
+  bool compression_enabled() const {
+    return compression_option_ == ENABLE_COMPRESSION;
+  }
+
+  void SetHpackIndexingPolicy(HpackEncoder::IndexingPolicy policy) {
+    GetHpackEncoder()->SetIndexingPolicy(std::move(policy));
+  }
+
+  // Updates the maximum size of the header encoder compression table.
+  void UpdateHeaderEncoderTableSize(uint32_t value);
+
+  // Returns the maximum size of the header encoder compression table.
+  size_t header_encoder_table_size() const;
+
+  // Get (and lazily initialize) the HPACK encoder state.
+  HpackEncoder* GetHpackEncoder();
+
+  // Gets the HPACK encoder state. Returns nullptr if the encoder has not been
+  // initialized.
+  const HpackEncoder* GetHpackEncoder() const { return hpack_encoder_.get(); }
+
+ protected:
+  friend class test::SpdyFramerPeer;
+  friend class test::SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
+  friend class test::SpdyFramerTest_PushPromiseFramesWithIterator_Test;
+
+  // Iteratively converts a SpdyFrameIR into an appropriate sequence of Spdy
+  // frames.
+  // Example usage:
+  // std::unique_ptr<SpdyFrameSequence> it = CreateIterator(framer, frame_ir);
+  // while (it->HasNextFrame()) {
+  //   if(it->NextFrame(output) == 0) {
+  //     // Write failed;
+  //   }
+  // }
+  class QUICHE_EXPORT SpdyFrameIterator : public SpdyFrameSequence {
+   public:
+    // Creates an iterator with the provided framer.
+    // Does not take ownership of |framer|.
+    // |framer| must outlive this instance.
+    explicit SpdyFrameIterator(SpdyFramer* framer);
+    ~SpdyFrameIterator() override;
+
+    // Serializes the next frame in the sequence to |output|. Returns the number
+    // of bytes written to |output|.
+    size_t NextFrame(ZeroCopyOutputBuffer* output) override;
+
+    // Returns true iff there is at least one more frame in the sequence.
+    bool HasNextFrame() const override;
+
+    // SpdyFrameIterator is neither copyable nor movable.
+    SpdyFrameIterator(const SpdyFrameIterator&) = delete;
+    SpdyFrameIterator& operator=(const SpdyFrameIterator&) = delete;
+
+   protected:
+    virtual size_t GetFrameSizeSansBlock() const = 0;
+    virtual bool SerializeGivenEncoding(const std::string& encoding,
+                                        ZeroCopyOutputBuffer* output) const = 0;
+
+    SpdyFramer* GetFramer() const { return framer_; }
+
+    void SetEncoder(const SpdyFrameWithHeaderBlockIR* ir) {
+      encoder_ =
+          framer_->GetHpackEncoder()->EncodeHeaderSet(ir->header_block());
+    }
+
+    bool has_next_frame() const { return has_next_frame_; }
+
+   private:
+    SpdyFramer* const framer_;
+    std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoder_;
+    bool is_first_frame_;
+    bool has_next_frame_;
+  };
+
+  // Iteratively converts a SpdyHeadersIR (with a possibly huge
+  // Http2HeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
+  // write to the output.
+  class QUICHE_EXPORT SpdyHeaderFrameIterator : public SpdyFrameIterator {
+   public:
+    // Does not take ownership of |framer|. Take ownership of |headers_ir|.
+    SpdyHeaderFrameIterator(SpdyFramer* framer,
+                            std::unique_ptr<const SpdyHeadersIR> headers_ir);
+
+    ~SpdyHeaderFrameIterator() override;
+
+   private:
+    const SpdyFrameIR& GetIR() const override;
+    size_t GetFrameSizeSansBlock() const override;
+    bool SerializeGivenEncoding(const std::string& encoding,
+                                ZeroCopyOutputBuffer* output) const override;
+
+    const std::unique_ptr<const SpdyHeadersIR> headers_ir_;
+  };
+
+  // Iteratively converts a SpdyPushPromiseIR (with a possibly huge
+  // Http2HeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
+  // write to the output.
+  class QUICHE_EXPORT SpdyPushPromiseFrameIterator : public SpdyFrameIterator {
+   public:
+    // Does not take ownership of |framer|. Take ownership of |push_promise_ir|.
+    SpdyPushPromiseFrameIterator(
+        SpdyFramer* framer,
+        std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir);
+
+    ~SpdyPushPromiseFrameIterator() override;
+
+   private:
+    const SpdyFrameIR& GetIR() const override;
+    size_t GetFrameSizeSansBlock() const override;
+    bool SerializeGivenEncoding(const std::string& encoding,
+                                ZeroCopyOutputBuffer* output) const override;
+
+    const std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir_;
+  };
+
+  // Converts a SpdyFrameIR into one Spdy frame (a sequence of length 1), and
+  // write it to the output.
+  class QUICHE_EXPORT SpdyControlFrameIterator : public SpdyFrameSequence {
+   public:
+    SpdyControlFrameIterator(SpdyFramer* framer,
+                             std::unique_ptr<const SpdyFrameIR> frame_ir);
+    ~SpdyControlFrameIterator() override;
+
+    size_t NextFrame(ZeroCopyOutputBuffer* output) override;
+
+    bool HasNextFrame() const override;
+
+    const SpdyFrameIR& GetIR() const override;
+
+   private:
+    SpdyFramer* const framer_;
+    std::unique_ptr<const SpdyFrameIR> frame_ir_;
+    bool has_next_frame_ = true;
+  };
+
+ private:
+  void SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers,
+                                     uint8_t* flags, size_t* size,
+                                     std::string* hpack_encoding, int* weight,
+                                     size_t* length_field);
+  void SerializePushPromiseBuilderHelper(const SpdyPushPromiseIR& push_promise,
+                                         uint8_t* flags,
+                                         std::string* hpack_encoding,
+                                         size_t* size);
+
+  std::unique_ptr<HpackEncoder> hpack_encoder_;
+
+  SpdyFramerDebugVisitorInterface* debug_visitor_;
+
+  // Determines whether HPACK compression is used.
+  const CompressionOption compression_option_;
+};
+
+}  // namespace spdy
+
+#endif  // QUICHE_HTTP2_CORE_SPDY_FRAMER_H_
diff --git a/quiche/spdy/core/spdy_framer_test.cc b/quiche/http2/core/spdy_framer_test.cc
similarity index 99%
rename from quiche/spdy/core/spdy_framer_test.cc
rename to quiche/http2/core/spdy_framer_test.cc
index 8b0ae57..aa0b205 100644
--- a/quiche/spdy/core/spdy_framer_test.cc
+++ b/quiche/http2/core/spdy_framer_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "quiche/spdy/core/spdy_framer.h"
+#include "quiche/http2/core/spdy_framer.h"
 
 #include <stdlib.h>
 
@@ -19,20 +19,20 @@
 #include "absl/base/macros.h"
 #include "absl/strings/string_view.h"
 #include "quiche/http2/core/array_output_buffer.h"
+#include "quiche/http2/core/http2_frame_decoder_adapter.h"
 #include "quiche/http2/core/recording_headers_handler.h"
+#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
+#include "quiche/http2/core/spdy_bitmasks.h"
+#include "quiche/http2/core/spdy_frame_builder.h"
 #include "quiche/http2/core/spdy_headers_handler_interface.h"
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/http2/hpack/hpack_encoder.h"
 #include "quiche/http2/test_tools/mock_spdy_framer_visitor.h"
 #include "quiche/http2/test_tools/spdy_test_utils.h"
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/common/platform/api/quiche_test.h"
 #include "quiche/common/quiche_text_utils.h"
-#include "quiche/spdy/core/http2_frame_decoder_adapter.h"
 #include "quiche/spdy/core/http2_header_block.h"
-#include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
-#include "quiche/spdy/core/spdy_bitmasks.h"
-#include "quiche/spdy/core/spdy_frame_builder.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 using ::http2::Http2DecoderAdapter;
 using ::testing::_;
diff --git a/quiche/http2/core/spdy_no_op_visitor.cc b/quiche/http2/core/spdy_no_op_visitor.cc
index 8361524..f3d04a9 100644
--- a/quiche/http2/core/spdy_no_op_visitor.cc
+++ b/quiche/http2/core/spdy_no_op_visitor.cc
@@ -8,7 +8,7 @@
 #include <type_traits>
 
 #include "quiche/http2/core/spdy_headers_handler_interface.h"
-#include "quiche/spdy/core/spdy_protocol.h"
+#include "quiche/http2/core/spdy_protocol.h"
 
 namespace spdy {
 
diff --git a/quiche/http2/core/spdy_no_op_visitor.h b/quiche/http2/core/spdy_no_op_visitor.h
index fc822bf..4f4ff53 100644
--- a/quiche/http2/core/spdy_no_op_visitor.h
+++ b/quiche/http2/core/spdy_no_op_visitor.h
@@ -14,11 +14,11 @@
 #include <string>
 
 #include "absl/strings/string_view.h"
+#include "quiche/http2/core/http2_frame_decoder_adapter.h"
+#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
 #include "quiche/http2/core/spdy_headers_handler_interface.h"
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/common/platform/api/quiche_export.h"
-#include "quiche/spdy/core/http2_frame_decoder_adapter.h"
-#include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 namespace spdy {
 
diff --git a/quiche/spdy/core/spdy_protocol.cc b/quiche/http2/core/spdy_protocol.cc
similarity index 99%
rename from quiche/spdy/core/spdy_protocol.cc
rename to quiche/http2/core/spdy_protocol.cc
index fc3b971..ae3f662 100644
--- a/quiche/spdy/core/spdy_protocol.cc
+++ b/quiche/http2/core/spdy_protocol.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "quiche/spdy/core/spdy_protocol.h"
+#include "quiche/http2/core/spdy_protocol.h"
 
 #include <cstddef>
 #include <cstdint>
@@ -14,11 +14,11 @@
 
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
+#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
 #include "quiche/common/platform/api/quiche_bug_tracker.h"
 #include "quiche/common/platform/api/quiche_flag_utils.h"
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/spdy/core/http2_header_block.h"
-#include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
 
 namespace spdy {
 
diff --git a/quiche/http2/core/spdy_protocol.h b/quiche/http2/core/spdy_protocol.h
new file mode 100644
index 0000000..24bb9d5
--- /dev/null
+++ b/quiche/http2/core/spdy_protocol.h
@@ -0,0 +1,1101 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains some protocol structures for use with SPDY 3 and HTTP 2
+// The SPDY 3 spec can be found at:
+// http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3
+
+#ifndef QUICHE_HTTP2_CORE_SPDY_PROTOCOL_H_
+#define QUICHE_HTTP2_CORE_SPDY_PROTOCOL_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <iosfwd>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/variant.h"
+#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
+#include "quiche/http2/core/spdy_bitmasks.h"
+#include "quiche/common/platform/api/quiche_export.h"
+#include "quiche/common/platform/api/quiche_flags.h"
+#include "quiche/common/platform/api/quiche_logging.h"
+#include "quiche/spdy/core/http2_header_block.h"
+
+namespace spdy {
+
+// A stream ID is a 31-bit entity.
+using SpdyStreamId = uint32_t;
+
+// A SETTINGS ID is a 16-bit entity.
+using SpdySettingsId = uint16_t;
+
+// Specifies the stream ID used to denote the current session (for
+// flow control).
+inline constexpr SpdyStreamId kSessionFlowControlStreamId = 0;
+
+// 0 is not a valid stream ID for any other purpose than flow control.
+inline constexpr SpdyStreamId kInvalidStreamId = 0;
+
+// Max stream id.
+inline constexpr SpdyStreamId kMaxStreamId = 0x7fffffff;
+
+// The maximum possible frame payload size allowed by the spec.
+inline constexpr uint32_t kSpdyMaxFrameSizeLimit = (1 << 24) - 1;
+
+// The initial value for the maximum frame payload size as per the spec. This is
+// the maximum control frame size we accept.
+inline constexpr uint32_t kHttp2DefaultFramePayloadLimit = 1 << 14;
+
+// The maximum size of the control frames that we send, including the size of
+// the header. This limit is arbitrary. We can enforce it here or at the
+// application layer. We chose the framing layer, but this can be changed (or
+// removed) if necessary later down the line.
+inline constexpr size_t kHttp2MaxControlFrameSendSize =
+    kHttp2DefaultFramePayloadLimit - 1;
+
+// Number of octets in the frame header.
+inline constexpr size_t kFrameHeaderSize = 9;
+
+// The initial value for the maximum frame payload size as per the spec. This is
+// the maximum control frame size we accept.
+inline constexpr uint32_t kHttp2DefaultFrameSizeLimit =
+    kHttp2DefaultFramePayloadLimit + kFrameHeaderSize;
+
+// The initial value for the maximum size of the header list, "unlimited" (max
+// unsigned 32-bit int) as per the spec.
+inline constexpr uint32_t kSpdyInitialHeaderListSizeLimit = 0xFFFFFFFF;
+
+// Maximum window size for a Spdy stream or session.
+inline constexpr int32_t kSpdyMaximumWindowSize =
+    0x7FFFFFFF;  // Max signed 32bit int
+
+// Maximum padding size in octets for one DATA or HEADERS or PUSH_PROMISE frame.
+inline constexpr int32_t kPaddingSizePerFrame = 256;
+
+// The HTTP/2 connection preface, which must be the first bytes sent by the
+// client upon starting an HTTP/2 connection, and which must be followed by a
+// SETTINGS frame.  Note that even though |kHttp2ConnectionHeaderPrefix| is
+// defined as a string literal with a null terminator, the actual connection
+// preface is only the first |kHttp2ConnectionHeaderPrefixSize| bytes, which
+// excludes the null terminator.
+QUICHE_EXPORT extern const char* const kHttp2ConnectionHeaderPrefix;
+inline constexpr int kHttp2ConnectionHeaderPrefixSize = 24;
+
+// Wire values for HTTP2 frame types.
+enum class SpdyFrameType : uint8_t {
+  DATA = 0x00,
+  HEADERS = 0x01,
+  PRIORITY = 0x02,
+  RST_STREAM = 0x03,
+  SETTINGS = 0x04,
+  PUSH_PROMISE = 0x05,
+  PING = 0x06,
+  GOAWAY = 0x07,
+  WINDOW_UPDATE = 0x08,
+  CONTINUATION = 0x09,
+  // ALTSVC is a public extension.
+  ALTSVC = 0x0a,
+  PRIORITY_UPDATE = 0x10,
+  ACCEPT_CH = 0x89,
+};
+
+// Flags on data packets.
+enum SpdyDataFlags {
+  DATA_FLAG_NONE = 0x00,
+  DATA_FLAG_FIN = 0x01,
+  DATA_FLAG_PADDED = 0x08,
+};
+
+// Flags on control packets
+enum SpdyControlFlags {
+  CONTROL_FLAG_NONE = 0x00,
+  CONTROL_FLAG_FIN = 0x01,
+};
+
+enum SpdyPingFlags {
+  PING_FLAG_ACK = 0x01,
+};
+
+// Used by HEADERS, PUSH_PROMISE, and CONTINUATION.
+enum SpdyHeadersFlags {
+  HEADERS_FLAG_END_HEADERS = 0x04,
+  HEADERS_FLAG_PADDED = 0x08,
+  HEADERS_FLAG_PRIORITY = 0x20,
+};
+
+enum SpdyPushPromiseFlags {
+  PUSH_PROMISE_FLAG_END_PUSH_PROMISE = 0x04,
+  PUSH_PROMISE_FLAG_PADDED = 0x08,
+};
+
+enum Http2SettingsControlFlags {
+  SETTINGS_FLAG_ACK = 0x01,
+};
+
+// Wire values of HTTP/2 setting identifiers.
+enum SpdyKnownSettingsId : SpdySettingsId {
+  // HPACK header table maximum size.
+  SETTINGS_HEADER_TABLE_SIZE = 0x1,
+  SETTINGS_MIN = SETTINGS_HEADER_TABLE_SIZE,
+  // Whether or not server push (PUSH_PROMISE) is enabled.
+  SETTINGS_ENABLE_PUSH = 0x2,
+  // The maximum number of simultaneous live streams in each direction.
+  SETTINGS_MAX_CONCURRENT_STREAMS = 0x3,
+  // Initial window size in bytes
+  SETTINGS_INITIAL_WINDOW_SIZE = 0x4,
+  // The size of the largest frame payload that a receiver is willing to accept.
+  SETTINGS_MAX_FRAME_SIZE = 0x5,
+  // The maximum size of header list that the sender is prepared to accept.
+  SETTINGS_MAX_HEADER_LIST_SIZE = 0x6,
+  // Enable Websockets over HTTP/2, see
+  // https://httpwg.org/specs/rfc8441.html
+  SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x8,
+  // Disable HTTP/2 priorities, see
+  // https://tools.ietf.org/html/draft-ietf-httpbis-priority-02.
+  SETTINGS_DEPRECATE_HTTP2_PRIORITIES = 0x9,
+  SETTINGS_MAX = SETTINGS_DEPRECATE_HTTP2_PRIORITIES,
+  // Experimental setting used to configure an alternative write scheduler.
+  SETTINGS_EXPERIMENT_SCHEDULER = 0xFF45,
+};
+
+// This explicit operator is needed, otherwise compiler finds
+// overloaded operator to be ambiguous.
+QUICHE_EXPORT std::ostream& operator<<(std::ostream& out,
+                                       SpdyKnownSettingsId id);
+
+// This operator is needed, because SpdyFrameType is an enum class,
+// therefore implicit conversion to underlying integer type is not allowed.
+QUICHE_EXPORT std::ostream& operator<<(std::ostream& out,
+                                       SpdyFrameType frame_type);
+
+using SettingsMap = std::map<SpdySettingsId, uint32_t>;
+
+// HTTP/2 error codes, RFC 7540 Section 7.
+enum SpdyErrorCode : uint32_t {
+  ERROR_CODE_NO_ERROR = 0x0,
+  ERROR_CODE_PROTOCOL_ERROR = 0x1,
+  ERROR_CODE_INTERNAL_ERROR = 0x2,
+  ERROR_CODE_FLOW_CONTROL_ERROR = 0x3,
+  ERROR_CODE_SETTINGS_TIMEOUT = 0x4,
+  ERROR_CODE_STREAM_CLOSED = 0x5,
+  ERROR_CODE_FRAME_SIZE_ERROR = 0x6,
+  ERROR_CODE_REFUSED_STREAM = 0x7,
+  ERROR_CODE_CANCEL = 0x8,
+  ERROR_CODE_COMPRESSION_ERROR = 0x9,
+  ERROR_CODE_CONNECT_ERROR = 0xa,
+  ERROR_CODE_ENHANCE_YOUR_CALM = 0xb,
+  ERROR_CODE_INADEQUATE_SECURITY = 0xc,
+  ERROR_CODE_HTTP_1_1_REQUIRED = 0xd,
+  ERROR_CODE_MAX = ERROR_CODE_HTTP_1_1_REQUIRED
+};
+
+// Type of priority write scheduler.
+enum class WriteSchedulerType {
+  LIFO,  // Last added stream has the highest priority.
+  SPDY,  // Uses SPDY priorities described in
+         // https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1#TOC-2.3.3-Stream-priority.
+  HTTP2,  // Uses HTTP2 (tree-style) priority described in
+          // https://tools.ietf.org/html/rfc7540#section-5.3.
+  FIFO,   // Stream with the smallest stream ID has the highest priority.
+};
+
+// A SPDY priority is a number between 0 and 7 (inclusive).
+typedef uint8_t SpdyPriority;
+
+// Lowest and Highest here refer to SPDY priorities as described in
+// https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1#TOC-2.3.3-Stream-priority
+inline constexpr SpdyPriority kV3HighestPriority = 0;
+inline constexpr SpdyPriority kV3LowestPriority = 7;
+
+// Returns SPDY 3.x priority value clamped to the valid range of [0, 7].
+QUICHE_EXPORT SpdyPriority ClampSpdy3Priority(SpdyPriority priority);
+
+// HTTP/2 stream weights are integers in range [1, 256], as specified in RFC
+// 7540 section 5.3.2. Default stream weight is defined in section 5.3.5.
+inline constexpr int kHttp2MinStreamWeight = 1;
+inline constexpr int kHttp2MaxStreamWeight = 256;
+inline constexpr int kHttp2DefaultStreamWeight = 16;
+
+// Returns HTTP/2 weight clamped to the valid range of [1, 256].
+QUICHE_EXPORT int ClampHttp2Weight(int weight);
+
+// Maps SPDY 3.x priority value in range [0, 7] to HTTP/2 weight value in range
+// [1, 256], where priority 0 (i.e. highest precedence) corresponds to maximum
+// weight 256 and priority 7 (lowest precedence) corresponds to minimum weight
+// 1.
+QUICHE_EXPORT int Spdy3PriorityToHttp2Weight(SpdyPriority priority);
+
+// Maps HTTP/2 weight value in range [1, 256] to SPDY 3.x priority value in
+// range [0, 7], where minimum weight 1 corresponds to priority 7 (lowest
+// precedence) and maximum weight 256 corresponds to priority 0 (highest
+// precedence).
+QUICHE_EXPORT SpdyPriority Http2WeightToSpdy3Priority(int weight);
+
+// Reserved ID for root stream of HTTP/2 stream dependency tree, as specified
+// in RFC 7540 section 5.3.1.
+const unsigned int kHttp2RootStreamId = 0;
+
+typedef uint64_t SpdyPingId;
+
+// Returns true if a given on-the-wire enumeration of a frame type is defined
+// in a standardized HTTP/2 specification, false otherwise.
+QUICHE_EXPORT bool IsDefinedFrameType(uint8_t frame_type_field);
+
+// Parses a frame type from an on-the-wire enumeration.
+// Behavior is undefined for invalid frame type fields; consumers should first
+// use IsValidFrameType() to verify validity of frame type fields.
+QUICHE_EXPORT SpdyFrameType ParseFrameType(uint8_t frame_type_field);
+
+// Serializes a frame type to the on-the-wire value.
+QUICHE_EXPORT uint8_t SerializeFrameType(SpdyFrameType frame_type);
+
+// (HTTP/2) All standard frame types except WINDOW_UPDATE are
+// (stream-specific xor connection-level). Returns false iff we know
+// the given frame type does not align with the given streamID.
+QUICHE_EXPORT bool IsValidHTTP2FrameStreamId(
+    SpdyStreamId current_frame_stream_id, SpdyFrameType frame_type_field);
+
+// Serialize |frame_type| to string for logging/debugging.
+QUICHE_EXPORT const char* FrameTypeToString(SpdyFrameType frame_type);
+
+// If |wire_setting_id| is the on-the-wire representation of a defined SETTINGS
+// parameter, parse it to |*setting_id| and return true.
+QUICHE_EXPORT bool ParseSettingsId(SpdySettingsId wire_setting_id,
+                                   SpdyKnownSettingsId* setting_id);
+
+// Returns a string representation of the |id| for logging/debugging. Returns
+// the |id| prefixed with "SETTINGS_UNKNOWN_" for unknown SETTINGS IDs. To parse
+// the |id| into a SpdyKnownSettingsId (if applicable), use ParseSettingsId().
+QUICHE_EXPORT std::string SettingsIdToString(SpdySettingsId id);
+
+// Parse |wire_error_code| to a SpdyErrorCode.
+// Treat unrecognized error codes as INTERNAL_ERROR
+// as recommended by the HTTP/2 specification.
+QUICHE_EXPORT SpdyErrorCode ParseErrorCode(uint32_t wire_error_code);
+
+// Serialize RST_STREAM or GOAWAY frame error code to string
+// for logging/debugging.
+QUICHE_EXPORT const char* ErrorCodeToString(SpdyErrorCode error_code);
+
+// Serialize |type| to string for logging/debugging.
+QUICHE_EXPORT const char* WriteSchedulerTypeToString(WriteSchedulerType type);
+
+// Minimum size of a frame, in octets.
+inline constexpr size_t kFrameMinimumSize = kFrameHeaderSize;
+
+// Minimum frame size for variable size frame types (includes mandatory fields),
+// frame size for fixed size frames, in octets.
+
+inline constexpr size_t kDataFrameMinimumSize = kFrameHeaderSize;
+inline constexpr size_t kHeadersFrameMinimumSize = kFrameHeaderSize;
+// PRIORITY frame has stream_dependency (4 octets) and weight (1 octet) fields.
+inline constexpr size_t kPriorityFrameSize = kFrameHeaderSize + 5;
+// RST_STREAM frame has error_code (4 octets) field.
+inline constexpr size_t kRstStreamFrameSize = kFrameHeaderSize + 4;
+inline constexpr size_t kSettingsFrameMinimumSize = kFrameHeaderSize;
+inline constexpr size_t kSettingsOneSettingSize =
+    sizeof(uint32_t) + sizeof(SpdySettingsId);
+// PUSH_PROMISE frame has promised_stream_id (4 octet) field.
+inline constexpr size_t kPushPromiseFrameMinimumSize = kFrameHeaderSize + 4;
+// PING frame has opaque_bytes (8 octet) field.
+inline constexpr size_t kPingFrameSize = kFrameHeaderSize + 8;
+// GOAWAY frame has last_stream_id (4 octet) and error_code (4 octet) fields.
+inline constexpr size_t kGoawayFrameMinimumSize = kFrameHeaderSize + 8;
+// WINDOW_UPDATE frame has window_size_increment (4 octet) field.
+inline constexpr size_t kWindowUpdateFrameSize = kFrameHeaderSize + 4;
+inline constexpr size_t kContinuationFrameMinimumSize = kFrameHeaderSize;
+// ALTSVC frame has origin_len (2 octets) field.
+inline constexpr size_t kGetAltSvcFrameMinimumSize = kFrameHeaderSize + 2;
+// PRIORITY_UPDATE frame has prioritized_stream_id (4 octets) field.
+inline constexpr size_t kPriorityUpdateFrameMinimumSize = kFrameHeaderSize + 4;
+// ACCEPT_CH frame may have empty payload.
+inline constexpr size_t kAcceptChFrameMinimumSize = kFrameHeaderSize;
+// Each ACCEPT_CH frame entry has a 16-bit origin length and a 16-bit value
+// length.
+inline constexpr size_t kAcceptChFramePerEntryOverhead = 4;
+
+// Maximum possible configurable size of a frame in octets.
+inline constexpr size_t kMaxFrameSizeLimit =
+    kSpdyMaxFrameSizeLimit + kFrameHeaderSize;
+// Size of a header block size field.
+inline constexpr size_t kSizeOfSizeField = sizeof(uint32_t);
+// Initial window size for a stream in bytes.
+inline constexpr int32_t kInitialStreamWindowSize = 64 * 1024 - 1;
+// Initial window size for a session in bytes.
+inline constexpr int32_t kInitialSessionWindowSize = 64 * 1024 - 1;
+// The NPN string for HTTP2, "h2".
+QUICHE_EXPORT extern const char* const kHttp2Npn;
+// An estimate of the HPACK overhead for each header field in bytes, intended to
+// be no smaller than actual overhead, based on the literal header field
+// representation in RFC 7541 Section 6.2 (with or without indexing):
+//   - 1 byte for the opcode.
+//   - 2 bytes for the name length (assuming new name).
+//   - 3 bytes for the value length.
+// TODO(b/322146543): Remove the `New` suffix with deprecation of
+// --gfe2_reloadable_flag_http2_add_hpack_overhead_bytes2.
+inline constexpr size_t kPerHeaderHpackOverheadNew = 6;
+// An estimate size of the HPACK overhead for each header field. 1 bytes for
+// indexed literal, 1 bytes for key literal and length encoding, and 2 bytes for
+// value literal and length encoding.
+// TODO(b/322146543): Remove with deprecation of
+// --gfe2_reloadable_flag_http2_add_hpack_overhead_bytes2.
+inline constexpr size_t kPerHeaderHpackOverheadOld = 4;
+
+// Names of pseudo-headers defined for HTTP/2 requests.
+QUICHE_EXPORT extern const char* const kHttp2AuthorityHeader;
+QUICHE_EXPORT extern const char* const kHttp2MethodHeader;
+QUICHE_EXPORT extern const char* const kHttp2PathHeader;
+QUICHE_EXPORT extern const char* const kHttp2SchemeHeader;
+QUICHE_EXPORT extern const char* const kHttp2ProtocolHeader;
+
+// Name of pseudo-header defined for HTTP/2 responses.
+QUICHE_EXPORT extern const char* const kHttp2StatusHeader;
+
+QUICHE_EXPORT size_t GetNumberRequiredContinuationFrames(size_t size);
+
+// Variant type that is either a SPDY 3.x priority value, or else an HTTP/2
+// stream dependency tuple {parent stream ID, weight, exclusive bit}. Templated
+// to allow for use by QUIC code; SPDY and HTTP/2 code should use the concrete
+// type instantiation SpdyStreamPrecedence.
+template <typename StreamIdType>
+class QUICHE_EXPORT StreamPrecedence {
+ public:
+  // Constructs instance that is a SPDY 3.x priority. Clamps priority value to
+  // the valid range [0, 7].
+  explicit StreamPrecedence(SpdyPriority priority)
+      : precedence_(ClampSpdy3Priority(priority)) {}
+
+  // Constructs instance that is an HTTP/2 stream weight, parent stream ID, and
+  // exclusive bit. Clamps stream weight to the valid range [1, 256].
+  StreamPrecedence(StreamIdType parent_id, int weight, bool is_exclusive)
+      : precedence_(Http2StreamDependency{parent_id, ClampHttp2Weight(weight),
+                                          is_exclusive}) {}
+
+  // Intentionally copyable, to support pass by value.
+  StreamPrecedence(const StreamPrecedence& other) = default;
+  StreamPrecedence& operator=(const StreamPrecedence& other) = default;
+
+  // Returns true if this instance is a SPDY 3.x priority, or false if this
+  // instance is an HTTP/2 stream dependency.
+  bool is_spdy3_priority() const {
+    return absl::holds_alternative<SpdyPriority>(precedence_);
+  }
+
+  // Returns SPDY 3.x priority value. If |is_spdy3_priority()| is true, this is
+  // the value provided at construction, clamped to the legal priority
+  // range. Otherwise, it is the HTTP/2 stream weight mapped to a SPDY 3.x
+  // priority value, where minimum weight 1 corresponds to priority 7 (lowest
+  // precedence) and maximum weight 256 corresponds to priority 0 (highest
+  // precedence).
+  SpdyPriority spdy3_priority() const {
+    return is_spdy3_priority()
+               ? absl::get<SpdyPriority>(precedence_)
+               : Http2WeightToSpdy3Priority(
+                     absl::get<Http2StreamDependency>(precedence_).weight);
+  }
+
+  // Returns HTTP/2 parent stream ID. If |is_spdy3_priority()| is false, this is
+  // the value provided at construction, otherwise it is |kHttp2RootStreamId|.
+  StreamIdType parent_id() const {
+    return is_spdy3_priority()
+               ? kHttp2RootStreamId
+               : absl::get<Http2StreamDependency>(precedence_).parent_id;
+  }
+
+  // Returns HTTP/2 stream weight. If |is_spdy3_priority()| is false, this is
+  // the value provided at construction, clamped to the legal weight
+  // range. Otherwise, it is the SPDY 3.x priority value mapped to an HTTP/2
+  // stream weight, where priority 0 (i.e. highest precedence) corresponds to
+  // maximum weight 256 and priority 7 (lowest precedence) corresponds to
+  // minimum weight 1.
+  int weight() const {
+    return is_spdy3_priority()
+               ? Spdy3PriorityToHttp2Weight(
+                     absl::get<SpdyPriority>(precedence_))
+               : absl::get<Http2StreamDependency>(precedence_).weight;
+  }
+
+  // Returns HTTP/2 parent stream exclusivity. If |is_spdy3_priority()| is
+  // false, this is the value provided at construction, otherwise it is false.
+  bool is_exclusive() const {
+    return absl::holds_alternative<Http2StreamDependency>(precedence_) &&
+           absl::get<Http2StreamDependency>(precedence_).is_exclusive;
+  }
+
+  // Facilitates test assertions.
+  bool operator==(const StreamPrecedence& other) const {
+    return precedence_ == other.precedence_;
+  }
+
+  bool operator!=(const StreamPrecedence& other) const {
+    return !(*this == other);
+  }
+
+ private:
+  struct QUICHE_EXPORT Http2StreamDependency {
+    StreamIdType parent_id;
+    int weight;
+    bool is_exclusive;
+
+    bool operator==(const Http2StreamDependency& other) const {
+      return parent_id == other.parent_id && weight == other.weight &&
+             is_exclusive == other.is_exclusive;
+    }
+  };
+
+  absl::variant<SpdyPriority, Http2StreamDependency> precedence_;
+};
+
+typedef StreamPrecedence<SpdyStreamId> SpdyStreamPrecedence;
+
+class SpdyFrameVisitor;
+
+// Intermediate representation for HTTP2 frames.
+class QUICHE_EXPORT SpdyFrameIR {
+ public:
+  virtual ~SpdyFrameIR() {}
+
+  virtual void Visit(SpdyFrameVisitor* visitor) const = 0;
+  virtual SpdyFrameType frame_type() const = 0;
+  SpdyStreamId stream_id() const { return stream_id_; }
+  virtual bool fin() const;
+  // Returns an estimate of the size of the serialized frame, without applying
+  // compression. May not be exact, but implementations should return the same
+  // value for a const frame.
+  virtual size_t size() const = 0;
+
+  // Returns the number of bytes of flow control window that would be consumed
+  // by this frame if written to the wire.
+  virtual int flow_control_window_consumed() const;
+
+ protected:
+  SpdyFrameIR() : stream_id_(0) {}
+  explicit SpdyFrameIR(SpdyStreamId stream_id) : stream_id_(stream_id) {}
+  SpdyFrameIR(const SpdyFrameIR&) = delete;
+  SpdyFrameIR& operator=(const SpdyFrameIR&) = delete;
+
+ private:
+  SpdyStreamId stream_id_;
+};
+
+// Abstract class intended to be inherited by IRs that have the option of a FIN
+// flag.
+class QUICHE_EXPORT SpdyFrameWithFinIR : public SpdyFrameIR {
+ public:
+  ~SpdyFrameWithFinIR() override {}
+  bool fin() const override;
+  void set_fin(bool fin) { fin_ = fin; }
+
+ protected:
+  explicit SpdyFrameWithFinIR(SpdyStreamId stream_id)
+      : SpdyFrameIR(stream_id), fin_(false) {}
+  SpdyFrameWithFinIR(const SpdyFrameWithFinIR&) = delete;
+  SpdyFrameWithFinIR& operator=(const SpdyFrameWithFinIR&) = delete;
+
+ private:
+  bool fin_;
+};
+
+// Abstract class intended to be inherited by IRs that contain a header
+// block. Implies SpdyFrameWithFinIR.
+class QUICHE_EXPORT SpdyFrameWithHeaderBlockIR : public SpdyFrameWithFinIR {
+ public:
+  ~SpdyFrameWithHeaderBlockIR() override;
+
+  const Http2HeaderBlock& header_block() const { return header_block_; }
+  void set_header_block(Http2HeaderBlock header_block) {
+    // Deep copy.
+    header_block_ = std::move(header_block);
+  }
+  void SetHeader(absl::string_view name, absl::string_view value) {
+    header_block_[name] = value;
+  }
+
+ protected:
+  SpdyFrameWithHeaderBlockIR(SpdyStreamId stream_id,
+                             Http2HeaderBlock header_block);
+  SpdyFrameWithHeaderBlockIR(const SpdyFrameWithHeaderBlockIR&) = delete;
+  SpdyFrameWithHeaderBlockIR& operator=(const SpdyFrameWithHeaderBlockIR&) =
+      delete;
+
+ private:
+  Http2HeaderBlock header_block_;
+};
+
+class QUICHE_EXPORT SpdyDataIR : public SpdyFrameWithFinIR {
+ public:
+  // Performs a deep copy on data.
+  SpdyDataIR(SpdyStreamId stream_id, absl::string_view data);
+
+  // Performs a deep copy on data.
+  SpdyDataIR(SpdyStreamId stream_id, const char* data);
+
+  // Moves data into data_store_. Makes a copy if passed a non-movable string.
+  SpdyDataIR(SpdyStreamId stream_id, std::string data);
+
+  // Use in conjunction with SetDataShallow() for shallow-copy on data.
+  explicit SpdyDataIR(SpdyStreamId stream_id);
+  SpdyDataIR(const SpdyDataIR&) = delete;
+  SpdyDataIR& operator=(const SpdyDataIR&) = delete;
+
+  ~SpdyDataIR() override;
+
+  const char* data() const { return data_; }
+  size_t data_len() const { return data_len_; }
+
+  bool padded() const { return padded_; }
+
+  int padding_payload_len() const { return padding_payload_len_; }
+
+  void set_padding_len(int padding_len) {
+    QUICHE_DCHECK_GT(padding_len, 0);
+    QUICHE_DCHECK_LE(padding_len, kPaddingSizePerFrame);
+    padded_ = true;
+    // The pad field takes one octet on the wire.
+    padding_payload_len_ = padding_len - 1;
+  }
+
+  // Deep-copy of data (keep private copy).
+  void SetDataDeep(absl::string_view data) {
+    data_store_ = std::make_unique<std::string>(data.data(), data.size());
+    data_ = data_store_->data();
+    data_len_ = data.size();
+  }
+
+  // Shallow-copy of data (do not keep private copy).
+  void SetDataShallow(absl::string_view data) {
+    data_store_.reset();
+    data_ = data.data();
+    data_len_ = data.size();
+  }
+
+  // Use this method if we don't have a contiguous buffer and only
+  // need a length.
+  void SetDataShallow(size_t len) {
+    data_store_.reset();
+    data_ = nullptr;
+    data_len_ = len;
+  }
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  int flow_control_window_consumed() const override;
+
+  size_t size() const override;
+
+ private:
+  // Used to store data that this SpdyDataIR should own.
+  std::unique_ptr<std::string> data_store_;
+  const char* data_;
+  size_t data_len_;
+
+  bool padded_;
+  // padding_payload_len_ = desired padding length - len(padding length field).
+  int padding_payload_len_;
+};
+
+class QUICHE_EXPORT SpdyRstStreamIR : public SpdyFrameIR {
+ public:
+  SpdyRstStreamIR(SpdyStreamId stream_id, SpdyErrorCode error_code);
+  SpdyRstStreamIR(const SpdyRstStreamIR&) = delete;
+  SpdyRstStreamIR& operator=(const SpdyRstStreamIR&) = delete;
+
+  ~SpdyRstStreamIR() override;
+
+  SpdyErrorCode error_code() const { return error_code_; }
+  void set_error_code(SpdyErrorCode error_code) { error_code_ = error_code; }
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  size_t size() const override;
+
+ private:
+  SpdyErrorCode error_code_;
+};
+
+class QUICHE_EXPORT SpdySettingsIR : public SpdyFrameIR {
+ public:
+  SpdySettingsIR();
+  SpdySettingsIR(const SpdySettingsIR&) = delete;
+  SpdySettingsIR& operator=(const SpdySettingsIR&) = delete;
+  ~SpdySettingsIR() override;
+
+  // Overwrites as appropriate.
+  const SettingsMap& values() const { return values_; }
+  void AddSetting(SpdySettingsId id, int32_t value) { values_[id] = value; }
+
+  bool is_ack() const { return is_ack_; }
+  void set_is_ack(bool is_ack) { is_ack_ = is_ack; }
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  size_t size() const override;
+
+ private:
+  SettingsMap values_;
+  bool is_ack_;
+};
+
+class QUICHE_EXPORT SpdyPingIR : public SpdyFrameIR {
+ public:
+  explicit SpdyPingIR(SpdyPingId id) : id_(id), is_ack_(false) {}
+  SpdyPingIR(const SpdyPingIR&) = delete;
+  SpdyPingIR& operator=(const SpdyPingIR&) = delete;
+  SpdyPingId id() const { return id_; }
+
+  bool is_ack() const { return is_ack_; }
+  void set_is_ack(bool is_ack) { is_ack_ = is_ack; }
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  size_t size() const override;
+
+ private:
+  SpdyPingId id_;
+  bool is_ack_;
+};
+
+class QUICHE_EXPORT SpdyGoAwayIR : public SpdyFrameIR {
+ public:
+  // References description, doesn't copy it, so description must outlast
+  // this SpdyGoAwayIR.
+  SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyErrorCode error_code,
+               absl::string_view description);
+
+  // References description, doesn't copy it, so description must outlast
+  // this SpdyGoAwayIR.
+  SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyErrorCode error_code,
+               const char* description);
+
+  // Moves description into description_store_, so caller doesn't need to
+  // keep description live after constructing this SpdyGoAwayIR.
+  SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyErrorCode error_code,
+               std::string description);
+  SpdyGoAwayIR(const SpdyGoAwayIR&) = delete;
+  SpdyGoAwayIR& operator=(const SpdyGoAwayIR&) = delete;
+
+  ~SpdyGoAwayIR() override;
+
+  SpdyStreamId last_good_stream_id() const { return last_good_stream_id_; }
+  void set_last_good_stream_id(SpdyStreamId last_good_stream_id) {
+    QUICHE_DCHECK_EQ(0u, last_good_stream_id & ~kStreamIdMask);
+    last_good_stream_id_ = last_good_stream_id;
+  }
+  SpdyErrorCode error_code() const { return error_code_; }
+  void set_error_code(SpdyErrorCode error_code) {
+    // TODO(hkhalil): Check valid ranges of error_code?
+    error_code_ = error_code;
+  }
+
+  const absl::string_view& description() const { return description_; }
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  size_t size() const override;
+
+ private:
+  SpdyStreamId last_good_stream_id_;
+  SpdyErrorCode error_code_;
+  const std::string description_store_;
+  const absl::string_view description_;
+};
+
+class QUICHE_EXPORT SpdyHeadersIR : public SpdyFrameWithHeaderBlockIR {
+ public:
+  explicit SpdyHeadersIR(SpdyStreamId stream_id)
+      : SpdyHeadersIR(stream_id, Http2HeaderBlock()) {}
+  SpdyHeadersIR(SpdyStreamId stream_id, Http2HeaderBlock header_block)
+      : SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)) {}
+  SpdyHeadersIR(const SpdyHeadersIR&) = delete;
+  SpdyHeadersIR& operator=(const SpdyHeadersIR&) = delete;
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  size_t size() const override;
+
+  bool has_priority() const { return has_priority_; }
+  void set_has_priority(bool has_priority) { has_priority_ = has_priority; }
+  int weight() const { return weight_; }
+  void set_weight(int weight) { weight_ = weight; }
+  SpdyStreamId parent_stream_id() const { return parent_stream_id_; }
+  void set_parent_stream_id(SpdyStreamId id) { parent_stream_id_ = id; }
+  bool exclusive() const { return exclusive_; }
+  void set_exclusive(bool exclusive) { exclusive_ = exclusive; }
+  bool padded() const { return padded_; }
+  int padding_payload_len() const { return padding_payload_len_; }
+  void set_padding_len(int padding_len) {
+    QUICHE_DCHECK_GT(padding_len, 0);
+    QUICHE_DCHECK_LE(padding_len, kPaddingSizePerFrame);
+    padded_ = true;
+    // The pad field takes one octet on the wire.
+    padding_payload_len_ = padding_len - 1;
+  }
+
+ private:
+  bool has_priority_ = false;
+  int weight_ = kHttp2DefaultStreamWeight;
+  SpdyStreamId parent_stream_id_ = 0;
+  bool exclusive_ = false;
+  bool padded_ = false;
+  int padding_payload_len_ = 0;
+  const bool add_hpack_overhead_bytes_ =
+      GetQuicheReloadableFlag(http2_add_hpack_overhead_bytes2);
+};
+
+class QUICHE_EXPORT SpdyWindowUpdateIR : public SpdyFrameIR {
+ public:
+  SpdyWindowUpdateIR(SpdyStreamId stream_id, int32_t delta)
+      : SpdyFrameIR(stream_id) {
+    set_delta(delta);
+  }
+  SpdyWindowUpdateIR(const SpdyWindowUpdateIR&) = delete;
+  SpdyWindowUpdateIR& operator=(const SpdyWindowUpdateIR&) = delete;
+
+  int32_t delta() const { return delta_; }
+  void set_delta(int32_t delta) {
+    QUICHE_DCHECK_LE(0, delta);
+    QUICHE_DCHECK_LE(delta, kSpdyMaximumWindowSize);
+    delta_ = delta;
+  }
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  size_t size() const override;
+
+ private:
+  int32_t delta_;
+};
+
+class QUICHE_EXPORT SpdyPushPromiseIR : public SpdyFrameWithHeaderBlockIR {
+ public:
+  SpdyPushPromiseIR(SpdyStreamId stream_id, SpdyStreamId promised_stream_id)
+      : SpdyPushPromiseIR(stream_id, promised_stream_id, Http2HeaderBlock()) {}
+  SpdyPushPromiseIR(SpdyStreamId stream_id, SpdyStreamId promised_stream_id,
+                    Http2HeaderBlock header_block)
+      : SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)),
+        promised_stream_id_(promised_stream_id),
+        padded_(false),
+        padding_payload_len_(0) {}
+  SpdyPushPromiseIR(const SpdyPushPromiseIR&) = delete;
+  SpdyPushPromiseIR& operator=(const SpdyPushPromiseIR&) = delete;
+  SpdyStreamId promised_stream_id() const { return promised_stream_id_; }
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  size_t size() const override;
+
+  bool padded() const { return padded_; }
+  int padding_payload_len() const { return padding_payload_len_; }
+  void set_padding_len(int padding_len) {
+    QUICHE_DCHECK_GT(padding_len, 0);
+    QUICHE_DCHECK_LE(padding_len, kPaddingSizePerFrame);
+    padded_ = true;
+    // The pad field takes one octet on the wire.
+    padding_payload_len_ = padding_len - 1;
+  }
+
+ private:
+  SpdyStreamId promised_stream_id_;
+
+  bool padded_;
+  int padding_payload_len_;
+};
+
+class QUICHE_EXPORT SpdyContinuationIR : public SpdyFrameIR {
+ public:
+  explicit SpdyContinuationIR(SpdyStreamId stream_id);
+  SpdyContinuationIR(const SpdyContinuationIR&) = delete;
+  SpdyContinuationIR& operator=(const SpdyContinuationIR&) = delete;
+  ~SpdyContinuationIR() override;
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  bool end_headers() const { return end_headers_; }
+  void set_end_headers(bool end_headers) { end_headers_ = end_headers; }
+  const std::string& encoding() const { return encoding_; }
+  void take_encoding(std::string encoding) { encoding_ = std::move(encoding); }
+  size_t size() const override;
+
+ private:
+  std::string encoding_;
+  bool end_headers_;
+};
+
+class QUICHE_EXPORT SpdyAltSvcIR : public SpdyFrameIR {
+ public:
+  explicit SpdyAltSvcIR(SpdyStreamId stream_id);
+  SpdyAltSvcIR(const SpdyAltSvcIR&) = delete;
+  SpdyAltSvcIR& operator=(const SpdyAltSvcIR&) = delete;
+  ~SpdyAltSvcIR() override;
+
+  std::string origin() const { return origin_; }
+  const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector() const {
+    return altsvc_vector_;
+  }
+
+  void set_origin(std::string origin) { origin_ = std::move(origin); }
+  void add_altsvc(const SpdyAltSvcWireFormat::AlternativeService& altsvc) {
+    altsvc_vector_.push_back(altsvc);
+  }
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  size_t size() const override;
+
+ private:
+  std::string origin_;
+  SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_;
+};
+
+class QUICHE_EXPORT SpdyPriorityIR : public SpdyFrameIR {
+ public:
+  SpdyPriorityIR(SpdyStreamId stream_id, SpdyStreamId parent_stream_id,
+                 int weight, bool exclusive)
+      : SpdyFrameIR(stream_id),
+        parent_stream_id_(parent_stream_id),
+        weight_(weight),
+        exclusive_(exclusive) {}
+  SpdyPriorityIR(const SpdyPriorityIR&) = delete;
+  SpdyPriorityIR& operator=(const SpdyPriorityIR&) = delete;
+  SpdyStreamId parent_stream_id() const { return parent_stream_id_; }
+  int weight() const { return weight_; }
+  bool exclusive() const { return exclusive_; }
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  size_t size() const override;
+
+ private:
+  SpdyStreamId parent_stream_id_;
+  int weight_;
+  bool exclusive_;
+};
+
+class QUICHE_EXPORT SpdyPriorityUpdateIR : public SpdyFrameIR {
+ public:
+  SpdyPriorityUpdateIR(SpdyStreamId stream_id,
+                       SpdyStreamId prioritized_stream_id,
+                       std::string priority_field_value)
+      : SpdyFrameIR(stream_id),
+        prioritized_stream_id_(prioritized_stream_id),
+        priority_field_value_(std::move(priority_field_value)) {}
+  SpdyPriorityUpdateIR(const SpdyPriorityUpdateIR&) = delete;
+  SpdyPriorityUpdateIR& operator=(const SpdyPriorityUpdateIR&) = delete;
+  SpdyStreamId prioritized_stream_id() const { return prioritized_stream_id_; }
+  const std::string& priority_field_value() const {
+    return priority_field_value_;
+  }
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  size_t size() const override;
+
+ private:
+  SpdyStreamId prioritized_stream_id_;
+  std::string priority_field_value_;
+};
+
+struct QUICHE_EXPORT AcceptChOriginValuePair {
+  std::string origin;
+  std::string value;
+  bool operator==(const AcceptChOriginValuePair& rhs) const {
+    return origin == rhs.origin && value == rhs.value;
+  }
+};
+
+class QUICHE_EXPORT SpdyAcceptChIR : public SpdyFrameIR {
+ public:
+  SpdyAcceptChIR(std::vector<AcceptChOriginValuePair> entries)
+      : entries_(std::move(entries)) {}
+  SpdyAcceptChIR(const SpdyAcceptChIR&) = delete;
+  SpdyAcceptChIR& operator=(const SpdyAcceptChIR&) = delete;
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  size_t size() const override;
+
+  const std::vector<AcceptChOriginValuePair>& entries() const {
+    return entries_;
+  }
+
+ private:
+  std::vector<AcceptChOriginValuePair> entries_;
+};
+
+// Represents a frame of unrecognized type.
+class QUICHE_EXPORT SpdyUnknownIR : public SpdyFrameIR {
+ public:
+  SpdyUnknownIR(SpdyStreamId stream_id, uint8_t type, uint8_t flags,
+                std::string payload)
+      : SpdyFrameIR(stream_id),
+        type_(type),
+        flags_(flags),
+        length_(payload.size()),
+        payload_(std::move(payload)) {}
+  SpdyUnknownIR(const SpdyUnknownIR&) = delete;
+  SpdyUnknownIR& operator=(const SpdyUnknownIR&) = delete;
+  uint8_t type() const { return type_; }
+  uint8_t flags() const { return flags_; }
+  size_t length() const { return length_; }
+  const std::string& payload() const { return payload_; }
+
+  void Visit(SpdyFrameVisitor* visitor) const override;
+
+  SpdyFrameType frame_type() const override;
+
+  int flow_control_window_consumed() const override;
+
+  size_t size() const override;
+
+ protected:
+  // Allows subclasses to overwrite the default payload length.
+  void set_length(size_t length) { length_ = length; }
+
+ private:
+  uint8_t type_;
+  uint8_t flags_;
+  size_t length_;
+  const std::string payload_;
+};
+
+class QUICHE_EXPORT SpdySerializedFrame {
+ public:
+  SpdySerializedFrame() : size_(0) {}
+
+  // Creates a valid SpdySerializedFrame using a pre-created buffer.
+  SpdySerializedFrame(std::unique_ptr<char[]> data, size_t size)
+      : frame_(std::move(data)), size_(size) {}
+
+  SpdySerializedFrame(SpdySerializedFrame&& other)
+      : frame_(std::move(other.frame_)), size_(other.size_) {}
+
+  SpdySerializedFrame(const SpdySerializedFrame&) = delete;
+  SpdySerializedFrame& operator=(const SpdySerializedFrame&) = delete;
+
+  SpdySerializedFrame& operator=(SpdySerializedFrame&& other) {
+    // Take over |other|.
+    frame_ = std::move(other.frame_);
+    size_ = other.size_;
+    return *this;
+  }
+
+  ~SpdySerializedFrame() = default;
+
+  // Provides access to the frame bytes, which is a buffer containing the frame
+  // packed as expected for sending over the wire.
+  char* data() const { return frame_.get(); }
+
+  // Returns the actual size of the underlying buffer.
+  size_t size() const { return size_; }
+
+  operator absl::string_view() const {
+    return absl::string_view{frame_.get(), size_};
+  }
+
+ private:
+  std::unique_ptr<char[]> frame_;
+  size_t size_;
+};
+
+// This interface is for classes that want to process SpdyFrameIRs without
+// having to know what type they are.  An instance of this interface can be
+// passed to a SpdyFrameIR's Visit method, and the appropriate type-specific
+// method of this class will be called.
+class QUICHE_EXPORT SpdyFrameVisitor {
+ public:
+  SpdyFrameVisitor() {}
+  SpdyFrameVisitor(const SpdyFrameVisitor&) = delete;
+  SpdyFrameVisitor& operator=(const SpdyFrameVisitor&) = delete;
+  virtual ~SpdyFrameVisitor() {}
+
+  virtual void VisitRstStream(const SpdyRstStreamIR& rst_stream) = 0;
+  virtual void VisitSettings(const SpdySettingsIR& settings) = 0;
+  virtual void VisitPing(const SpdyPingIR& ping) = 0;
+  virtual void VisitGoAway(const SpdyGoAwayIR& goaway) = 0;
+  virtual void VisitHeaders(const SpdyHeadersIR& headers) = 0;
+  virtual void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) = 0;
+  virtual void VisitPushPromise(const SpdyPushPromiseIR& push_promise) = 0;
+  virtual void VisitContinuation(const SpdyContinuationIR& continuation) = 0;
+  virtual void VisitAltSvc(const SpdyAltSvcIR& altsvc) = 0;
+  virtual void VisitPriority(const SpdyPriorityIR& priority) = 0;
+  virtual void VisitData(const SpdyDataIR& data) = 0;
+  virtual void VisitPriorityUpdate(
+      const SpdyPriorityUpdateIR& priority_update) = 0;
+  virtual void VisitAcceptCh(const SpdyAcceptChIR& accept_ch) = 0;
+  virtual void VisitUnknown(const SpdyUnknownIR& /*unknown*/) {
+    // TODO(birenroy): make abstract.
+  }
+};
+
+// Optionally, and in addition to SpdyFramerVisitorInterface, a class supporting
+// SpdyFramerDebugVisitorInterface may be used in conjunction with SpdyFramer in
+// order to extract debug/internal information about the SpdyFramer as it
+// operates.
+//
+// Most HTTP2 implementations need not bother with this interface at all.
+class QUICHE_EXPORT SpdyFramerDebugVisitorInterface {
+ public:
+  virtual ~SpdyFramerDebugVisitorInterface() {}
+
+  // Called after compressing a frame with a payload of
+  // a list of name-value pairs.
+  // |payload_len| is the uncompressed payload size.
+  // |frame_len| is the compressed frame size.
+  virtual void OnSendCompressedFrame(SpdyStreamId /*stream_id*/,
+                                     SpdyFrameType /*type*/,
+                                     size_t /*payload_len*/,
+                                     size_t /*frame_len*/) {}
+
+  // Called when a frame containing a compressed payload of
+  // name-value pairs is received.
+  // |frame_len| is the compressed frame size.
+  virtual void OnReceiveCompressedFrame(SpdyStreamId /*stream_id*/,
+                                        SpdyFrameType /*type*/,
+                                        size_t /*frame_len*/) {}
+};
+
+// Calculates the number of bytes required to serialize a SpdyHeadersIR, not
+// including the bytes to be used for the encoded header set.
+size_t GetHeaderFrameSizeSansBlock(const SpdyHeadersIR& header_ir);
+
+// Calculates the number of bytes required to serialize a SpdyPushPromiseIR,
+// not including the bytes to be used for the encoded header set.
+size_t GetPushPromiseFrameSizeSansBlock(
+    const SpdyPushPromiseIR& push_promise_ir);
+
+}  // namespace spdy
+
+#endif  // QUICHE_HTTP2_CORE_SPDY_PROTOCOL_H_
diff --git a/quiche/spdy/core/spdy_protocol_test.cc b/quiche/http2/core/spdy_protocol_test.cc
similarity index 99%
rename from quiche/spdy/core/spdy_protocol_test.cc
rename to quiche/http2/core/spdy_protocol_test.cc
index 5a22bb2..7dbbe02 100644
--- a/quiche/spdy/core/spdy_protocol_test.cc
+++ b/quiche/http2/core/spdy_protocol_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "quiche/spdy/core/spdy_protocol.h"
+#include "quiche/http2/core/spdy_protocol.h"
 
 #include <iostream>
 #include <string>
diff --git a/quiche/http2/test_tools/http2_trace_printer.cc b/quiche/http2/test_tools/http2_trace_printer.cc
index 682f91b..cc04ce0 100644
--- a/quiche/http2/test_tools/http2_trace_printer.cc
+++ b/quiche/http2/test_tools/http2_trace_printer.cc
@@ -7,7 +7,7 @@
 #include "absl/strings/match.h"
 #include "absl/strings/string_view.h"
 #include "quiche/http2/core/http2_trace_logging.h"
-#include "quiche/spdy/core/spdy_protocol.h"
+#include "quiche/http2/core/spdy_protocol.h"
 
 namespace http2 {
 namespace test {
diff --git a/quiche/http2/test_tools/http2_trace_printer.h b/quiche/http2/test_tools/http2_trace_printer.h
index 6f27db1..3dc92af 100644
--- a/quiche/http2/test_tools/http2_trace_printer.h
+++ b/quiche/http2/test_tools/http2_trace_printer.h
@@ -4,10 +4,10 @@
 #include <cstddef>
 
 #include "absl/strings/string_view.h"
+#include "quiche/http2/core/http2_frame_decoder_adapter.h"
 #include "quiche/http2/core/http2_trace_logging.h"
 #include "quiche/http2/core/spdy_no_op_visitor.h"
 #include "quiche/common/platform/api/quiche_export.h"
-#include "quiche/spdy/core/http2_frame_decoder_adapter.h"
 
 namespace http2 {
 namespace test {
diff --git a/quiche/http2/test_tools/mock_spdy_framer_visitor.h b/quiche/http2/test_tools/mock_spdy_framer_visitor.h
index efec274..a66764d 100644
--- a/quiche/http2/test_tools/mock_spdy_framer_visitor.h
+++ b/quiche/http2/test_tools/mock_spdy_framer_visitor.h
@@ -11,13 +11,13 @@
 #include <string>
 
 #include "absl/strings/string_view.h"
+#include "quiche/http2/core/http2_frame_decoder_adapter.h"
 #include "quiche/http2/core/recording_headers_handler.h"
+#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
 #include "quiche/http2/core/spdy_headers_handler_interface.h"
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/common/platform/api/quiche_export.h"
 #include "quiche/common/platform/api/quiche_test.h"
-#include "quiche/spdy/core/http2_frame_decoder_adapter.h"
-#include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 // TODO(b/318698478): fix namespace and class name
 namespace spdy {
diff --git a/quiche/http2/test_tools/spdy_test_utils.cc b/quiche/http2/test_tools/spdy_test_utils.cc
index 70f30c8..766acce 100644
--- a/quiche/http2/test_tools/spdy_test_utils.cc
+++ b/quiche/http2/test_tools/spdy_test_utils.cc
@@ -10,10 +10,10 @@
 #include <memory>
 #include <string>
 
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/common/platform/api/quiche_test.h"
 #include "quiche/common/quiche_endian.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 namespace spdy {
 namespace test {
diff --git a/quiche/http2/test_tools/spdy_test_utils.h b/quiche/http2/test_tools/spdy_test_utils.h
index 1db9439..e59924f 100644
--- a/quiche/http2/test_tools/spdy_test_utils.h
+++ b/quiche/http2/test_tools/spdy_test_utils.h
@@ -10,8 +10,8 @@
 #include <string>
 
 #include "absl/strings/string_view.h"
+#include "quiche/http2/core/spdy_protocol.h"
 #include "quiche/spdy/core/http2_header_block.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 // TODO(b/318698478): update the namespace and file name
 namespace spdy {
diff --git a/quiche/spdy/core/http2_frame_decoder_adapter.h b/quiche/spdy/core/http2_frame_decoder_adapter.h
index 33249a3..dd78809 100644
--- a/quiche/spdy/core/http2_frame_decoder_adapter.h
+++ b/quiche/spdy/core/http2_frame_decoder_adapter.h
@@ -5,562 +5,6 @@
 #ifndef QUICHE_SPDY_CORE_HTTP2_FRAME_DECODER_ADAPTER_H_
 #define QUICHE_SPDY_CORE_HTTP2_FRAME_DECODER_ADAPTER_H_
 
-#include <stddef.h>
-
-#include <cstdint>
-#include <memory>
-#include <optional>
-#include <string>
-
-#include "absl/strings/string_view.h"
-#include "quiche/http2/core/spdy_headers_handler_interface.h"
-#include "quiche/http2/decoder/decode_status.h"
-#include "quiche/http2/decoder/http2_frame_decoder.h"
-#include "quiche/http2/decoder/http2_frame_decoder_listener.h"
-#include "quiche/http2/http2_constants.h"
-#include "quiche/http2/http2_structures.h"
-#include "quiche/common/platform/api/quiche_export.h"
-#include "quiche/spdy/core/hpack/hpack_decoder_adapter.h"
-#include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
-#include "quiche/spdy/core/spdy_protocol.h"
-
-namespace spdy {
-
-class SpdyFramerVisitorInterface;
-class ExtensionVisitorInterface;
-
-}  // namespace spdy
-
-// TODO(dahollings): Perform various renames/moves suggested in cl/164660364.
-
-namespace http2 {
-
-// Adapts SpdyFramer interface to use Http2FrameDecoder.
-class QUICHE_EXPORT Http2DecoderAdapter
-    : public http2::Http2FrameDecoderListener {
- public:
-  // HTTP2 states.
-  enum SpdyState {
-    SPDY_ERROR,
-    SPDY_READY_FOR_FRAME,  // Framer is ready for reading the next frame.
-    SPDY_FRAME_COMPLETE,  // Framer has finished reading a frame, need to reset.
-    SPDY_READING_COMMON_HEADER,
-    SPDY_CONTROL_FRAME_PAYLOAD,
-    SPDY_READ_DATA_FRAME_PADDING_LENGTH,
-    SPDY_CONSUME_PADDING,
-    SPDY_IGNORE_REMAINING_PAYLOAD,
-    SPDY_FORWARD_STREAM_FRAME,
-    SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK,
-    SPDY_CONTROL_FRAME_HEADER_BLOCK,
-    SPDY_GOAWAY_FRAME_PAYLOAD,
-    SPDY_SETTINGS_FRAME_HEADER,
-    SPDY_SETTINGS_FRAME_PAYLOAD,
-    SPDY_ALTSVC_FRAME_PAYLOAD,
-    SPDY_EXTENSION_FRAME_PAYLOAD,
-  };
-
-  // Framer error codes.
-  enum SpdyFramerError {
-    SPDY_NO_ERROR,
-    SPDY_INVALID_STREAM_ID,           // Stream ID is invalid
-    SPDY_INVALID_CONTROL_FRAME,       // Control frame is mal-formatted.
-    SPDY_CONTROL_PAYLOAD_TOO_LARGE,   // Control frame payload was too large.
-    SPDY_DECOMPRESS_FAILURE,          // There was an error decompressing.
-    SPDY_INVALID_PADDING,             // HEADERS or DATA frame padding invalid
-    SPDY_INVALID_DATA_FRAME_FLAGS,    // Data frame has invalid flags.
-    SPDY_UNEXPECTED_FRAME,            // Frame received out of order.
-    SPDY_INTERNAL_FRAMER_ERROR,       // SpdyFramer was used incorrectly.
-    SPDY_INVALID_CONTROL_FRAME_SIZE,  // Control frame not sized to spec
-    SPDY_OVERSIZED_PAYLOAD,           // Payload size was too large
-
-    // HttpDecoder or HttpDecoderAdapter error.
-    // See HpackDecodingError for description of each error code.
-    SPDY_HPACK_INDEX_VARINT_ERROR,
-    SPDY_HPACK_NAME_LENGTH_VARINT_ERROR,
-    SPDY_HPACK_VALUE_LENGTH_VARINT_ERROR,
-    SPDY_HPACK_NAME_TOO_LONG,
-    SPDY_HPACK_VALUE_TOO_LONG,
-    SPDY_HPACK_NAME_HUFFMAN_ERROR,
-    SPDY_HPACK_VALUE_HUFFMAN_ERROR,
-    SPDY_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE,
-    SPDY_HPACK_INVALID_INDEX,
-    SPDY_HPACK_INVALID_NAME_INDEX,
-    SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED,
-    SPDY_HPACK_INITIAL_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK,
-    SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING,
-    SPDY_HPACK_TRUNCATED_BLOCK,
-    SPDY_HPACK_FRAGMENT_TOO_LONG,
-    SPDY_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT,
-
-    // Set if the visitor no longer wishes to receive events for this
-    // connection.
-    SPDY_STOP_PROCESSING,
-
-    LAST_ERROR,  // Must be the last entry in the enum.
-  };
-
-  // For debugging.
-  static const char* StateToString(int state);
-  static const char* SpdyFramerErrorToString(SpdyFramerError spdy_framer_error);
-
-  Http2DecoderAdapter();
-  ~Http2DecoderAdapter() override;
-
-  Http2DecoderAdapter(const Http2DecoderAdapter&) = delete;
-  Http2DecoderAdapter& operator=(const Http2DecoderAdapter&) = delete;
-
-  // Set callbacks to be called from the framer.  A visitor must be set, or
-  // else the framer will likely crash.  It is acceptable for the visitor
-  // to do nothing.  If this is called multiple times, only the last visitor
-  // will be used.
-  void set_visitor(spdy::SpdyFramerVisitorInterface* visitor);
-  spdy::SpdyFramerVisitorInterface* visitor() const { return visitor_; }
-
-  // Set extension callbacks to be called from the framer or decoder. Optional.
-  // If called multiple times, only the last visitor will be used.
-  void set_extension_visitor(spdy::ExtensionVisitorInterface* visitor);
-  spdy::ExtensionVisitorInterface* extension_visitor() const {
-    return extension_;
-  }
-
-  // Set debug callbacks to be called from the framer. The debug visitor is
-  // completely optional and need not be set in order for normal operation.
-  // If this is called multiple times, only the last visitor will be used.
-  void set_debug_visitor(spdy::SpdyFramerDebugVisitorInterface* debug_visitor);
-  spdy::SpdyFramerDebugVisitorInterface* debug_visitor() const {
-    return debug_visitor_;
-  }
-
-  // Decode the |len| bytes of encoded HTTP/2 starting at |*data|. Returns
-  // the number of bytes consumed. It is safe to pass more bytes in than
-  // may be consumed. Should process (or otherwise buffer) as much as
-  // available.
-  //
-  // If the input contains the entirety of a DATA frame payload, GOAWAY frame
-  // Additional Debug Data field, or unknown frame payload, then the
-  // corresponding SpdyFramerVisitorInterface::OnStreamFrameData(),
-  // OnGoAwayFrameData(), or ExtensionVisitorInterface::OnFramePayload() method
-  // is guaranteed to be called exactly once, with the entire payload or field.
-  size_t ProcessInput(const char* data, size_t len);
-
-  // Current state of the decoder.
-  SpdyState state() const;
-
-  // Current error code (NO_ERROR if state != ERROR).
-  SpdyFramerError spdy_framer_error() const;
-
-  // Has any frame header looked like the start of an HTTP/1.1 (or earlier)
-  // response? Used to detect if a backend/server that we sent a request to
-  // has responded with an HTTP/1.1 (or earlier) response.
-  bool probable_http_response() const;
-
-  spdy::HpackDecoderAdapter& GetHpackDecoder() { return hpack_decoder_; }
-  const spdy::HpackDecoderAdapter& GetHpackDecoder() const {
-    return hpack_decoder_;
-  }
-
-  bool HasError() const;
-
-  // A visitor may call this method to indicate it no longer wishes to receive
-  // events for this connection.
-  void StopProcessing();
-
-  // Sets the limit on the size of received HTTP/2 frame payloads. Corresponds
-  // to SETTINGS_MAX_FRAME_SIZE as advertised to the peer.
-  void SetMaxFrameSize(size_t max_frame_size);
-
- private:
-  bool OnFrameHeader(const Http2FrameHeader& header) override;
-  void OnDataStart(const Http2FrameHeader& header) override;
-  void OnDataPayload(const char* data, size_t len) override;
-  void OnDataEnd() override;
-  void OnHeadersStart(const Http2FrameHeader& header) override;
-  void OnHeadersPriority(const Http2PriorityFields& priority) override;
-  void OnHpackFragment(const char* data, size_t len) override;
-  void OnHeadersEnd() override;
-  void OnPriorityFrame(const Http2FrameHeader& header,
-                       const Http2PriorityFields& priority) override;
-  void OnContinuationStart(const Http2FrameHeader& header) override;
-  void OnContinuationEnd() override;
-  void OnPadLength(size_t trailing_length) override;
-  void OnPadding(const char* padding, size_t skipped_length) override;
-  void OnRstStream(const Http2FrameHeader& header,
-                   Http2ErrorCode http2_error_code) override;
-  void OnSettingsStart(const Http2FrameHeader& header) override;
-  void OnSetting(const Http2SettingFields& setting_fields) override;
-  void OnSettingsEnd() override;
-  void OnSettingsAck(const Http2FrameHeader& header) override;
-  void OnPushPromiseStart(const Http2FrameHeader& header,
-                          const Http2PushPromiseFields& promise,
-                          size_t total_padding_length) override;
-  void OnPushPromiseEnd() override;
-  void OnPing(const Http2FrameHeader& header,
-              const Http2PingFields& ping) override;
-  void OnPingAck(const Http2FrameHeader& header,
-                 const Http2PingFields& ping) override;
-  void OnGoAwayStart(const Http2FrameHeader& header,
-                     const Http2GoAwayFields& goaway) override;
-  void OnGoAwayOpaqueData(const char* data, size_t len) override;
-  void OnGoAwayEnd() override;
-  void OnWindowUpdate(const Http2FrameHeader& header,
-                      uint32_t increment) override;
-  void OnAltSvcStart(const Http2FrameHeader& header, size_t origin_length,
-                     size_t value_length) override;
-  void OnAltSvcOriginData(const char* data, size_t len) override;
-  void OnAltSvcValueData(const char* data, size_t len) override;
-  void OnAltSvcEnd() override;
-  void OnPriorityUpdateStart(
-      const Http2FrameHeader& header,
-      const Http2PriorityUpdateFields& priority_update) override;
-  void OnPriorityUpdatePayload(const char* data, size_t len) override;
-  void OnPriorityUpdateEnd() override;
-  void OnUnknownStart(const Http2FrameHeader& header) override;
-  void OnUnknownPayload(const char* data, size_t len) override;
-  void OnUnknownEnd() override;
-  void OnPaddingTooLong(const Http2FrameHeader& header,
-                        size_t missing_length) override;
-  void OnFrameSizeError(const Http2FrameHeader& header) override;
-
-  size_t ProcessInputFrame(const char* data, size_t len);
-
-  void DetermineSpdyState(DecodeStatus status);
-  void ResetBetweenFrames();
-
-  void set_spdy_state(SpdyState v);
-
-  void SetSpdyErrorAndNotify(SpdyFramerError error, std::string detailed_error);
-
-  const Http2FrameHeader& frame_header() const;
-
-  uint32_t stream_id() const;
-  Http2FrameType frame_type() const;
-
-  size_t remaining_total_payload() const;
-
-  bool IsReadingPaddingLength();
-  bool IsSkippingPadding();
-  bool IsDiscardingPayload();
-  // Called from OnXyz or OnXyzStart methods to decide whether it is OK to
-  // handle the callback.
-  bool IsOkToStartFrame(const Http2FrameHeader& header);
-  bool HasRequiredStreamId(uint32_t stream_id);
-
-  bool HasRequiredStreamId(const Http2FrameHeader& header);
-
-  bool HasRequiredStreamIdZero(uint32_t stream_id);
-
-  bool HasRequiredStreamIdZero(const Http2FrameHeader& header);
-
-  void ReportReceiveCompressedFrame(const Http2FrameHeader& header);
-
-  void CommonStartHpackBlock();
-
-  // SpdyFramer calls HandleControlFrameHeadersData even if there are zero
-  // fragment bytes in the first frame, so do the same.
-  void MaybeAnnounceEmptyFirstHpackFragment();
-  void CommonHpackFragmentEnd();
-
-  // The most recently decoded frame header; invalid after we reached the end
-  // of that frame.
-  Http2FrameHeader frame_header_;
-
-  // If decoding an HPACK block that is split across multiple frames, this holds
-  // the frame header of the HEADERS or PUSH_PROMISE that started the block.
-  Http2FrameHeader hpack_first_frame_header_;
-
-  // Amount of trailing padding. Currently used just as an indicator of whether
-  // OnPadLength has been called.
-  std::optional<size_t> opt_pad_length_;
-
-  // Temporary buffers for the AltSvc fields.
-  std::string alt_svc_origin_;
-  std::string alt_svc_value_;
-
-  // Temporary buffers for PRIORITY_UPDATE fields.
-  uint32_t prioritized_stream_id_ = 0;
-  std::string priority_field_value_;
-
-  // Listener used if we transition to an error state; the listener ignores all
-  // the callbacks.
-  Http2FrameDecoderNoOpListener no_op_listener_;
-
-  spdy::SpdyFramerVisitorInterface* visitor_ = nullptr;
-  spdy::SpdyFramerDebugVisitorInterface* debug_visitor_ = nullptr;
-
-  // If non-null, unknown frames and settings are passed to the extension.
-  spdy::ExtensionVisitorInterface* extension_ = nullptr;
-
-  // The HPACK decoder to be used for this adapter.
-  spdy::HpackDecoderAdapter hpack_decoder_;
-
-  // The HTTP/2 frame decoder.
-  Http2FrameDecoder frame_decoder_;
-
-  // Next frame type expected. Currently only used for CONTINUATION frames,
-  // but could be used for detecting whether the first frame is a SETTINGS
-  // frame.
-  // TODO(jamessynge): Provide means to indicate that decoder should require
-  // SETTINGS frame as the first frame.
-  Http2FrameType expected_frame_type_;
-
-  // Attempt to duplicate the SpdyState and SpdyFramerError values that
-  // SpdyFramer sets. Values determined by getting tests to pass.
-  SpdyState spdy_state_ = SpdyState::SPDY_READY_FOR_FRAME;
-  SpdyFramerError spdy_framer_error_ = SpdyFramerError::SPDY_NO_ERROR;
-
-  // The limit on the size of received HTTP/2 payloads as specified in the
-  // SETTINGS_MAX_FRAME_SIZE advertised to peer.
-  size_t max_frame_size_ = spdy::kHttp2DefaultFramePayloadLimit;
-
-  // Has OnFrameHeader been called?
-  bool decoded_frame_header_ = false;
-
-  // Have we recorded an Http2FrameHeader for the current frame?
-  // We only do so if the decoder will make multiple callbacks for
-  // the frame; for example, for PING frames we don't make record
-  // the frame header, but for ALTSVC we do.
-  bool has_frame_header_ = false;
-
-  // Have we recorded an Http2FrameHeader for the current HPACK block?
-  // True only for multi-frame HPACK blocks.
-  bool has_hpack_first_frame_header_ = false;
-
-  // Has OnHeaders() already been called for current HEADERS block? Only
-  // meaningful between OnHeadersStart and OnHeadersPriority.
-  bool on_headers_called_ = false;
-
-  // Has OnHpackFragment() already been called for current HPACK block?
-  // SpdyFramer will pass an empty buffer to the HPACK decoder if a HEADERS
-  // or PUSH_PROMISE has no HPACK data in it (e.g. a HEADERS frame with only
-  // padding). Detect that condition and replicate the behavior using this
-  // field.
-  bool on_hpack_fragment_called_ = false;
-
-  // Have we seen a frame header that appears to be an HTTP/1 response?
-  bool latched_probable_http_response_ = false;
-
-  // Is expected_frame_type_ set?
-  bool has_expected_frame_type_ = false;
-
-  // Is the current frame payload destined for |extension_|?
-  bool handling_extension_payload_ = false;
-};
-
-}  // namespace http2
-
-namespace spdy {
-
-// Http2DecoderAdapter will use the given visitor implementing this
-// interface to deliver event callbacks as frames are decoded.
-//
-// Control frames that contain HTTP2 header blocks (HEADER, and PUSH_PROMISE)
-// are processed in fashion that allows the decompressed header block to be
-// delivered in chunks to the visitor.
-// The following steps are followed:
-//   1. OnHeaders, or OnPushPromise is called.
-//   2. OnHeaderFrameStart is called; visitor is expected to return an instance
-//      of SpdyHeadersHandlerInterface that will receive the header key-value
-//      pairs.
-//   3. OnHeaderFrameEnd is called, indicating that the full header block has
-//      been delivered for the control frame.
-// During step 2, if the visitor is not interested in accepting the header data,
-// it should return a no-op implementation of SpdyHeadersHandlerInterface.
-class QUICHE_EXPORT SpdyFramerVisitorInterface {
- public:
-  virtual ~SpdyFramerVisitorInterface() {}
-
-  // Called if an error is detected in the SpdyFrame protocol.
-  virtual void OnError(http2::Http2DecoderAdapter::SpdyFramerError error,
-                       std::string detailed_error) = 0;
-
-  // Called when the common header for a frame is received. Validating the
-  // common header occurs in later processing.
-  virtual void OnCommonHeader(SpdyStreamId /*stream_id*/, size_t /*length*/,
-                              uint8_t /*type*/, uint8_t /*flags*/) {}
-
-  // Called when a data frame header is received. The frame's data payload will
-  // be provided via subsequent calls to OnStreamFrameData().
-  // |stream_id| The stream receiving data.
-  // |length| The length of the payload in this DATA frame. Includes the length
-  //     of the data itself and potential padding.
-  // |fin| Whether the END_STREAM flag is set in the frame header.
-  virtual void OnDataFrameHeader(SpdyStreamId stream_id, size_t length,
-                                 bool fin) = 0;
-
-  // Called when data is received.
-  // |stream_id| The stream receiving data.
-  // |data| A buffer containing the data received.
-  // |len| The length of the data buffer.
-  virtual void OnStreamFrameData(SpdyStreamId stream_id, const char* data,
-                                 size_t len) = 0;
-
-  // Called when the other side has finished sending data on this stream.
-  // |stream_id| The stream that was receiving data.
-  virtual void OnStreamEnd(SpdyStreamId stream_id) = 0;
-
-  // Called when padding length field is received on a DATA frame.
-  // |stream_id| The stream receiving data.
-  // |value| The value of the padding length field.
-  virtual void OnStreamPadLength(SpdyStreamId /*stream_id*/, size_t /*value*/) {
-  }
-
-  // Called when padding is received (the trailing octets, not pad_len field) on
-  // a DATA frame.
-  // |stream_id| The stream receiving data.
-  // |len| The number of padding octets.
-  virtual void OnStreamPadding(SpdyStreamId stream_id, size_t len) = 0;
-
-  // Called just before processing the payload of a frame containing header
-  // data. Should return an implementation of SpdyHeadersHandlerInterface that
-  // will receive headers for stream |stream_id|. The caller will not take
-  // ownership of the headers handler. The same instance should remain live
-  // and be returned for all header frames comprising a logical header block
-  // (i.e. until OnHeaderFrameEnd() is called).
-  virtual SpdyHeadersHandlerInterface* OnHeaderFrameStart(
-      SpdyStreamId stream_id) = 0;
-
-  // Called after processing the payload of a frame containing header data.
-  virtual void OnHeaderFrameEnd(SpdyStreamId stream_id) = 0;
-
-  // Called when a RST_STREAM frame has been parsed.
-  virtual void OnRstStream(SpdyStreamId stream_id,
-                           SpdyErrorCode error_code) = 0;
-
-  // Called when a SETTINGS frame is received.
-  virtual void OnSettings() {}
-
-  // Called when a complete setting within a SETTINGS frame has been parsed.
-  // Note that |id| may or may not be a SETTINGS ID defined in the HTTP/2 spec.
-  virtual void OnSetting(SpdySettingsId id, uint32_t value) = 0;
-
-  // Called when a SETTINGS frame is received with the ACK flag set.
-  virtual void OnSettingsAck() {}
-
-  // Called before and after parsing SETTINGS id and value tuples.
-  virtual void OnSettingsEnd() = 0;
-
-  // Called when a PING frame has been parsed.
-  virtual void OnPing(SpdyPingId unique_id, bool is_ack) = 0;
-
-  // Called when a GOAWAY frame has been parsed.
-  virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
-                        SpdyErrorCode error_code) = 0;
-
-  // Called when a HEADERS frame is received.
-  // Note that header block data is not included. See OnHeaderFrameStart().
-  // |stream_id| The stream receiving the header.
-  // |payload_length| The length of the payload in this HEADERS frame. Includes
-  //     the length of the encoded header block and potential padding.
-  // |has_priority| Whether or not the headers frame included a priority value,
-  //     and stream dependency info.
-  // |weight| If |has_priority| is true, then weight (in the range [1, 256])
-  //     for the receiving stream, otherwise 0.
-  // |parent_stream_id| If |has_priority| is true the parent stream of the
-  //     receiving stream, else 0.
-  // |exclusive| If |has_priority| is true the exclusivity of dependence on the
-  //     parent stream, else false.
-  // |fin| Whether the END_STREAM flag is set in the frame header.
-  // |end| False if HEADERs frame is to be followed by a CONTINUATION frame,
-  //     or true if not.
-  virtual void OnHeaders(SpdyStreamId stream_id, size_t payload_length,
-                         bool has_priority, int weight,
-                         SpdyStreamId parent_stream_id, bool exclusive,
-                         bool fin, bool end) = 0;
-
-  // Called when a WINDOW_UPDATE frame has been parsed.
-  virtual void OnWindowUpdate(SpdyStreamId stream_id,
-                              int delta_window_size) = 0;
-
-  // Called when a goaway frame opaque data is available.
-  // |goaway_data| A buffer containing the opaque GOAWAY data chunk received.
-  // |len| The length of the header data buffer. A length of zero indicates
-  //       that the header data block has been completely sent.
-  // When this function returns true the visitor indicates that it accepted
-  // all of the data. Returning false indicates that that an error has
-  // occurred while processing the data. Default implementation returns true.
-  virtual bool OnGoAwayFrameData(const char* goaway_data, size_t len);
-
-  // Called when a PUSH_PROMISE frame is received.
-  // Note that header block data is not included. See OnHeaderFrameStart().
-  virtual void OnPushPromise(SpdyStreamId stream_id,
-                             SpdyStreamId promised_stream_id, bool end) = 0;
-
-  // Called when a CONTINUATION frame is received.
-  // Note that header block data is not included. See OnHeaderFrameStart().
-  // |stream_id| The stream receiving the CONTINUATION.
-  // |payload_length| The length of the payload in this CONTINUATION frame.
-  // |end| True if this CONTINUATION frame will not be followed by another
-  //     CONTINUATION frame.
-  virtual void OnContinuation(SpdyStreamId stream_id, size_t payload_length,
-                              bool end) = 0;
-
-  // Called when an ALTSVC frame has been parsed.
-  virtual void OnAltSvc(
-      SpdyStreamId /*stream_id*/, absl::string_view /*origin*/,
-      const SpdyAltSvcWireFormat::AlternativeServiceVector& /*altsvc_vector*/) {
-  }
-
-  // Called when a PRIORITY frame is received.
-  // |stream_id| The stream to update the priority of.
-  // |parent_stream_id| The parent stream of |stream_id|.
-  // |weight| Stream weight, in the range [1, 256].
-  // |exclusive| Whether |stream_id| should be an only child of
-  //     |parent_stream_id|.
-  virtual void OnPriority(SpdyStreamId stream_id, SpdyStreamId parent_stream_id,
-                          int weight, bool exclusive) = 0;
-
-  // Called when a PRIORITY_UPDATE frame is received on stream 0.
-  // |prioritized_stream_id| is the Prioritized Stream ID and
-  // |priority_field_value| is the Priority Field Value
-  // parsed from the frame payload.
-  virtual void OnPriorityUpdate(SpdyStreamId prioritized_stream_id,
-                                absl::string_view priority_field_value) = 0;
-
-  // Called when a frame type we don't recognize is received.
-  // Return true if this appears to be a valid extension frame, false otherwise.
-  // We distinguish between extension frames and nonsense by checking
-  // whether the stream id is valid.
-  // TODO(b/239060116): Remove this callback altogether.
-  virtual bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) = 0;
-
-  // Called when the common header for a non-standard frame is received. If the
-  // `length` is nonzero, the frame's payload will be provided via subsequent
-  // calls to OnUnknownFramePayload().
-  // |stream_id| The stream receiving the non-standard frame.
-  // |length| The length of the payload of the frame.
-  // |type| The type of the frame. This type is non-standard.
-  // |flags| The flags of the frame.
-  virtual void OnUnknownFrameStart(SpdyStreamId stream_id, size_t length,
-                                   uint8_t type, uint8_t flags) = 0;
-
-  // Called when a non-empty payload chunk for a non-standard frame is received.
-  // The payload for a single frame may be delivered as multiple calls to
-  // OnUnknownFramePayload(). Since the length field is passed in
-  // OnUnknownFrameStart(), there is no explicit indication of the end of the
-  // frame payload.
-  // |stream_id| The stream receiving the non-standard frame.
-  // |payload| The payload chunk, which will be non-empty.
-  virtual void OnUnknownFramePayload(SpdyStreamId stream_id,
-                                     absl::string_view payload) = 0;
-};
-
-class QUICHE_EXPORT ExtensionVisitorInterface {
- public:
-  virtual ~ExtensionVisitorInterface() {}
-
-  // Called when non-standard SETTINGS are received.
-  virtual void OnSetting(SpdySettingsId id, uint32_t value) = 0;
-
-  // Called when non-standard frames are received.
-  virtual bool OnFrameHeader(SpdyStreamId stream_id, size_t length,
-                             uint8_t type, uint8_t flags) = 0;
-
-  // The payload for a single frame may be delivered as multiple calls to
-  // OnFramePayload. Since the length field is passed in OnFrameHeader, there is
-  // no explicit indication of the end of the frame payload.
-  virtual void OnFramePayload(const char* data, size_t len) = 0;
-};
-
-}  // namespace spdy
+#include "quiche/http2/core/http2_frame_decoder_adapter.h"
 
 #endif  // QUICHE_SPDY_CORE_HTTP2_FRAME_DECODER_ADAPTER_H_
diff --git a/quiche/spdy/core/http2_frame_decoder_adapter_fuzzer.cc b/quiche/spdy/core/http2_frame_decoder_adapter_fuzzer.cc
index 188b46f..9073a75 100644
--- a/quiche/spdy/core/http2_frame_decoder_adapter_fuzzer.cc
+++ b/quiche/spdy/core/http2_frame_decoder_adapter_fuzzer.cc
@@ -1,8 +1,8 @@
 #include <cstddef>
 #include <cstdint>
 
+#include "quiche/http2/core/http2_frame_decoder_adapter.h"
 #include "quiche/http2/core/spdy_no_op_visitor.h"
-#include "quiche/spdy/core/http2_frame_decoder_adapter.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   spdy::SpdyNoOpVisitor visitor;
diff --git a/quiche/spdy/core/spdy_alt_svc_wire_format.h b/quiche/spdy/core/spdy_alt_svc_wire_format.h
index ec0c124..e8ab491 100644
--- a/quiche/spdy/core/spdy_alt_svc_wire_format.h
+++ b/quiche/spdy/core/spdy_alt_svc_wire_format.h
@@ -2,103 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This file contains data structures and utility functions used for serializing
-// and parsing alternative service header values, common to HTTP/1.1 header
-// fields and HTTP/2 and QUIC ALTSVC frames.  See specification at
-// https://httpwg.github.io/http-extensions/alt-svc.html.
-
 #ifndef QUICHE_SPDY_CORE_SPDY_ALT_SVC_WIRE_FORMAT_H_
 #define QUICHE_SPDY_CORE_SPDY_ALT_SVC_WIRE_FORMAT_H_
 
-#include <cstdint>
-#include <string>
-#include <vector>
-
-#include "absl/container/inlined_vector.h"
-#include "absl/strings/string_view.h"
-#include "quiche/common/platform/api/quiche_export.h"
-
-namespace spdy {
-
-namespace test {
-class SpdyAltSvcWireFormatPeer;
-}  // namespace test
-
-class QUICHE_EXPORT SpdyAltSvcWireFormat {
- public:
-  using VersionVector = absl::InlinedVector<uint32_t, 8>;
-
-  struct QUICHE_EXPORT AlternativeService {
-    std::string protocol_id;
-    std::string host;
-
-    // Default is 0: invalid port.
-    uint16_t port = 0;
-    // Default is one day.
-    uint32_t max_age_seconds = 86400;
-    // Default is empty: unspecified version.
-    VersionVector version;
-
-    AlternativeService();
-    AlternativeService(const std::string& protocol_id, const std::string& host,
-                       uint16_t port, uint32_t max_age_seconds,
-                       VersionVector version);
-    AlternativeService(const AlternativeService& other);
-    ~AlternativeService();
-
-    bool operator==(const AlternativeService& other) const {
-      return protocol_id == other.protocol_id && host == other.host &&
-             port == other.port && version == other.version &&
-             max_age_seconds == other.max_age_seconds;
-    }
-  };
-  // An empty vector means alternative services should be cleared for given
-  // origin.  Note that the wire format for this is the string "clear", not an
-  // empty value (which is invalid).
-  typedef std::vector<AlternativeService> AlternativeServiceVector;
-
-  friend class test::SpdyAltSvcWireFormatPeer;
-  static bool ParseHeaderFieldValue(absl::string_view value,
-                                    AlternativeServiceVector* altsvc_vector);
-  static std::string SerializeHeaderFieldValue(
-      const AlternativeServiceVector& altsvc_vector);
-
- private:
-  // Forward |*c| over space and tab or until |end| is reached.
-  static void SkipWhiteSpace(absl::string_view::const_iterator* c,
-                             absl::string_view::const_iterator end);
-  // Decode percent-decoded string between |c| and |end| into |*output|.
-  // Return true on success, false if input is invalid.
-  static bool PercentDecode(absl::string_view::const_iterator c,
-                            absl::string_view::const_iterator end,
-                            std::string* output);
-  // Parse the authority part of Alt-Svc between |c| and |end| into |*host| and
-  // |*port|.  Return true on success, false if input is invalid.
-  static bool ParseAltAuthority(absl::string_view::const_iterator c,
-                                absl::string_view::const_iterator end,
-                                std::string* host, uint16_t* port);
-  // Parse a positive integer between |c| and |end| into |*value|.
-  // Return true on success, false if input is not a positive integer or it
-  // cannot be represented on uint16_t.
-  static bool ParsePositiveInteger16(absl::string_view::const_iterator c,
-                                     absl::string_view::const_iterator end,
-                                     uint16_t* value);
-  // Parse a positive integer between |c| and |end| into |*value|.
-  // Return true on success, false if input is not a positive integer or it
-  // cannot be represented on uint32_t.
-  static bool ParsePositiveInteger32(absl::string_view::const_iterator c,
-                                     absl::string_view::const_iterator end,
-                                     uint32_t* value);
-  // Parse |c| as hexadecimal digit, case insensitive.  |c| must be [0-9a-fA-F].
-  // Output is between 0 and 15.
-  static char HexDigitToInt(char c);
-  // Parse |data| as hexadecimal number into |*value|.  |data| must only contain
-  // hexadecimal digits, no "0x" prefix.
-  // Return true on success, false if input is empty, not valid hexadecimal
-  // number, or cannot be represented on uint32_t.
-  static bool HexDecodeToUInt32(absl::string_view data, uint32_t* value);
-};
-
-}  // namespace spdy
+#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
 
 #endif  // QUICHE_SPDY_CORE_SPDY_ALT_SVC_WIRE_FORMAT_H_
diff --git a/quiche/spdy/core/spdy_bitmasks.h b/quiche/spdy/core/spdy_bitmasks.h
index 989e013..ae12b55 100644
--- a/quiche/spdy/core/spdy_bitmasks.h
+++ b/quiche/spdy/core/spdy_bitmasks.h
@@ -5,14 +5,6 @@
 #ifndef QUICHE_SPDY_CORE_SPDY_BITMASKS_H_
 #define QUICHE_SPDY_CORE_SPDY_BITMASKS_H_
 
-namespace spdy {
-
-// StreamId mask from the SpdyHeader
-inline constexpr unsigned int kStreamIdMask = 0x7fffffff;
-
-// Mask the lower 24 bits.
-inline constexpr unsigned int kLengthMask = 0xffffff;
-
-}  // namespace spdy
+#include "quiche/http2/core/spdy_bitmasks.h"
 
 #endif  // QUICHE_SPDY_CORE_SPDY_BITMASKS_H_
diff --git a/quiche/spdy/core/spdy_frame_builder.h b/quiche/spdy/core/spdy_frame_builder.h
index 829c878..f8f749b 100644
--- a/quiche/spdy/core/spdy_frame_builder.h
+++ b/quiche/spdy/core/spdy_frame_builder.h
@@ -5,136 +5,6 @@
 #ifndef QUICHE_SPDY_CORE_SPDY_FRAME_BUILDER_H_
 #define QUICHE_SPDY_CORE_SPDY_FRAME_BUILDER_H_
 
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-
-#include "absl/strings/string_view.h"
-#include "quiche/http2/core/zero_copy_output_buffer.h"
-#include "quiche/common/platform/api/quiche_bug_tracker.h"
-#include "quiche/common/platform/api/quiche_export.h"
-#include "quiche/common/quiche_endian.h"
-#include "quiche/spdy/core/spdy_protocol.h"
-
-namespace spdy {
-
-namespace test {
-class SpdyFrameBuilderPeer;
-}  // namespace test
-
-// This class provides facilities for basic binary value packing
-// into Spdy frames.
-//
-// The SpdyFrameBuilder supports appending primitive values (int, string, etc)
-// to a frame instance.  The SpdyFrameBuilder grows its internal memory buffer
-// dynamically to hold the sequence of primitive values.   The internal memory
-// buffer is exposed as the "data" of the SpdyFrameBuilder.
-class QUICHE_EXPORT SpdyFrameBuilder {
- public:
-  // Initializes a SpdyFrameBuilder with a buffer of given size
-  explicit SpdyFrameBuilder(size_t size);
-  // Doesn't take ownership of output.
-  SpdyFrameBuilder(size_t size, ZeroCopyOutputBuffer* output);
-
-  ~SpdyFrameBuilder();
-
-  // Returns the total size of the SpdyFrameBuilder's data, which may include
-  // multiple frames.
-  size_t length() const { return offset_ + length_; }
-
-  // Seeks forward by the given number of bytes. Useful in conjunction with
-  // GetWriteableBuffer() above.
-  bool Seek(size_t length);
-
-  // Populates this frame with a HTTP2 frame prefix using length information
-  // from |capacity_|. The given type must be a control frame type.
-  bool BeginNewFrame(SpdyFrameType type, uint8_t flags, SpdyStreamId stream_id);
-
-  // Populates this frame with a HTTP2 frame prefix with type and length
-  // information.  |type| must be a defined frame type.
-  bool BeginNewFrame(SpdyFrameType type, uint8_t flags, SpdyStreamId stream_id,
-                     size_t length);
-
-  // Populates this frame with a HTTP2 frame prefix with type and length
-  // information.  |raw_frame_type| may be a defined or undefined frame type.
-  bool BeginNewUncheckedFrame(uint8_t raw_frame_type, uint8_t flags,
-                              SpdyStreamId stream_id, size_t length);
-
-  // Takes the buffer from the SpdyFrameBuilder.
-  SpdySerializedFrame take() {
-    QUICHE_BUG_IF(spdy_bug_39_1, output_ != nullptr)
-        << "ZeroCopyOutputBuffer is used to build "
-        << "frames. take() shouldn't be called";
-    QUICHE_BUG_IF(spdy_bug_39_2, kMaxFrameSizeLimit < length_)
-        << "Frame length " << length_
-        << " is longer than the maximum possible allowed length.";
-    SpdySerializedFrame rv(std::move(buffer_), length());
-    capacity_ = 0;
-    length_ = 0;
-    offset_ = 0;
-    return rv;
-  }
-
-  // Methods for adding to the payload.  These values are appended to the end
-  // of the SpdyFrameBuilder payload. Note - binary integers are converted from
-  // host to network form.
-  bool WriteUInt8(uint8_t value) { return WriteBytes(&value, sizeof(value)); }
-  bool WriteUInt16(uint16_t value) {
-    value = quiche::QuicheEndian::HostToNet16(value);
-    return WriteBytes(&value, sizeof(value));
-  }
-  bool WriteUInt24(uint32_t value) {
-    value = quiche::QuicheEndian::HostToNet32(value);
-    return WriteBytes(reinterpret_cast<char*>(&value) + 1, sizeof(value) - 1);
-  }
-  bool WriteUInt32(uint32_t value) {
-    value = quiche::QuicheEndian::HostToNet32(value);
-    return WriteBytes(&value, sizeof(value));
-  }
-  bool WriteUInt64(uint64_t value) {
-    uint32_t upper =
-        quiche::QuicheEndian::HostToNet32(static_cast<uint32_t>(value >> 32));
-    uint32_t lower =
-        quiche::QuicheEndian::HostToNet32(static_cast<uint32_t>(value));
-    return (WriteBytes(&upper, sizeof(upper)) &&
-            WriteBytes(&lower, sizeof(lower)));
-  }
-  bool WriteStringPiece32(const absl::string_view value);
-  bool WriteBytes(const void* data, uint32_t data_len);
-
- private:
-  friend class test::SpdyFrameBuilderPeer;
-
-  // Populates this frame with a HTTP2 frame prefix with type and length
-  // information.
-  bool BeginNewFrameInternal(uint8_t raw_frame_type, uint8_t flags,
-                             SpdyStreamId stream_id, size_t length);
-
-  // Returns a writeable buffer of given size in bytes, to be appended to the
-  // currently written frame. Does bounds checking on length but does not
-  // increment the underlying iterator. To do so, consumers should subsequently
-  // call Seek().
-  // In general, consumers should use Write*() calls instead of this.
-  // Returns NULL on failure.
-  char* GetWritableBuffer(size_t length);
-  char* GetWritableOutput(size_t desired_length, size_t* actual_length);
-
-  // Checks to make sure that there is an appropriate amount of space for a
-  // write of given size, in bytes.
-  bool CanWrite(size_t length) const;
-
-  // A buffer to be created whenever a new frame needs to be written. Used only
-  // if |output_| is nullptr.
-  std::unique_ptr<char[]> buffer_;
-  // A pre-allocated buffer. If not-null, serialized frame data is written to
-  // this buffer.
-  ZeroCopyOutputBuffer* output_ = nullptr;  // Does not own.
-
-  size_t capacity_;  // Allocation size of payload, set by constructor.
-  size_t length_;    // Length of the latest frame in the buffer.
-  size_t offset_;    // Position at which the latest frame begins.
-};
-
-}  // namespace spdy
+#include "quiche/http2/core/spdy_frame_builder.h"
 
 #endif  // QUICHE_SPDY_CORE_SPDY_FRAME_BUILDER_H_
diff --git a/quiche/spdy/core/spdy_framer.h b/quiche/spdy/core/spdy_framer.h
index e660ed5..15fb6e6 100644
--- a/quiche/spdy/core/spdy_framer.h
+++ b/quiche/spdy/core/spdy_framer.h
@@ -5,367 +5,6 @@
 #ifndef QUICHE_SPDY_CORE_SPDY_FRAMER_H_
 #define QUICHE_SPDY_CORE_SPDY_FRAMER_H_
 
-#include <stddef.h>
-
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "quiche/http2/core/zero_copy_output_buffer.h"
-#include "quiche/http2/hpack/hpack_encoder.h"
-#include "quiche/common/platform/api/quiche_export.h"
-#include "quiche/spdy/core/spdy_protocol.h"
-
-namespace spdy {
-
-namespace test {
-
-class SpdyFramerPeer;
-class SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
-class SpdyFramerTest_PushPromiseFramesWithIterator_Test;
-
-}  // namespace test
-
-class QUICHE_EXPORT SpdyFrameSequence {
- public:
-  virtual ~SpdyFrameSequence() {}
-
-  // Serializes the next frame in the sequence to |output|. Returns the number
-  // of bytes written to |output|.
-  virtual size_t NextFrame(ZeroCopyOutputBuffer* output) = 0;
-
-  // Returns true iff there is at least one more frame in the sequence.
-  virtual bool HasNextFrame() const = 0;
-
-  // Get SpdyFrameIR of the frame to be serialized.
-  virtual const SpdyFrameIR& GetIR() const = 0;
-};
-
-class QUICHE_EXPORT SpdyFramer {
- public:
-  enum CompressionOption {
-    ENABLE_COMPRESSION,
-    DISABLE_COMPRESSION,
-  };
-
-  // Create a SpdyFrameSequence to serialize |frame_ir|.
-  static std::unique_ptr<SpdyFrameSequence> CreateIterator(
-      SpdyFramer* framer, std::unique_ptr<const SpdyFrameIR> frame_ir);
-
-  // Gets the serialized flags for the given |frame|.
-  static uint8_t GetSerializedFlags(const SpdyFrameIR& frame);
-
-  // Serialize a data frame.
-  static SpdySerializedFrame SerializeData(const SpdyDataIR& data_ir);
-  // Serializes the data frame header and optionally padding length fields,
-  // excluding actual data payload and padding.
-  static SpdySerializedFrame SerializeDataFrameHeaderWithPaddingLengthField(
-      const SpdyDataIR& data_ir);
-
-  // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE
-  // frame is used to implement per stream flow control.
-  static SpdySerializedFrame SerializeWindowUpdate(
-      const SpdyWindowUpdateIR& window_update);
-
-  explicit SpdyFramer(CompressionOption option);
-
-  virtual ~SpdyFramer();
-
-  // Set debug callbacks to be called from the framer. The debug visitor is
-  // completely optional and need not be set in order for normal operation.
-  // If this is called multiple times, only the last visitor will be used.
-  void set_debug_visitor(SpdyFramerDebugVisitorInterface* debug_visitor);
-
-  SpdySerializedFrame SerializeRstStream(
-      const SpdyRstStreamIR& rst_stream) const;
-
-  // Serializes a SETTINGS frame. The SETTINGS frame is
-  // used to communicate name/value pairs relevant to the communication channel.
-  SpdySerializedFrame SerializeSettings(const SpdySettingsIR& settings) const;
-
-  // Serializes a PING frame. The unique_id is used to
-  // identify the ping request/response.
-  SpdySerializedFrame SerializePing(const SpdyPingIR& ping) const;
-
-  // Serializes a GOAWAY frame. The GOAWAY frame is used
-  // prior to the shutting down of the TCP connection, and includes the
-  // stream_id of the last stream the sender of the frame is willing to process
-  // to completion.
-  SpdySerializedFrame SerializeGoAway(const SpdyGoAwayIR& goaway) const;
-
-  // Serializes a HEADERS frame. The HEADERS frame is used
-  // for sending headers.
-  SpdySerializedFrame SerializeHeaders(const SpdyHeadersIR& headers);
-
-  // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used
-  // to inform the client that it will be receiving an additional stream
-  // in response to the original request. The frame includes synthesized
-  // headers to explain the upcoming data.
-  SpdySerializedFrame SerializePushPromise(
-      const SpdyPushPromiseIR& push_promise);
-
-  // Serializes a CONTINUATION frame. The CONTINUATION frame is used
-  // to continue a sequence of header block fragments.
-  SpdySerializedFrame SerializeContinuation(
-      const SpdyContinuationIR& continuation) const;
-
-  // Serializes an ALTSVC frame. The ALTSVC frame advertises the
-  // availability of an alternative service to the client.
-  SpdySerializedFrame SerializeAltSvc(const SpdyAltSvcIR& altsvc);
-
-  // Serializes a PRIORITY frame. The PRIORITY frame advises a change in
-  // the relative priority of the given stream.
-  SpdySerializedFrame SerializePriority(const SpdyPriorityIR& priority) const;
-
-  // Serializes a PRIORITY_UPDATE frame.
-  // See https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html.
-  SpdySerializedFrame SerializePriorityUpdate(
-      const SpdyPriorityUpdateIR& priority_update) const;
-
-  // Serializes an ACCEPT_CH frame.  See
-  // https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02.
-  SpdySerializedFrame SerializeAcceptCh(const SpdyAcceptChIR& accept_ch) const;
-
-  // Serializes an unknown frame given a frame header and payload.
-  SpdySerializedFrame SerializeUnknown(const SpdyUnknownIR& unknown) const;
-
-  // Serialize a frame of unknown type.
-  SpdySerializedFrame SerializeFrame(const SpdyFrameIR& frame);
-
-  // Serialize a data frame.
-  bool SerializeData(const SpdyDataIR& data,
-                     ZeroCopyOutputBuffer* output) const;
-
-  // Serializes the data frame header and optionally padding length fields,
-  // excluding actual data payload and padding.
-  bool SerializeDataFrameHeaderWithPaddingLengthField(
-      const SpdyDataIR& data, ZeroCopyOutputBuffer* output) const;
-
-  bool SerializeRstStream(const SpdyRstStreamIR& rst_stream,
-                          ZeroCopyOutputBuffer* output) const;
-
-  // Serializes a SETTINGS frame. The SETTINGS frame is
-  // used to communicate name/value pairs relevant to the communication channel.
-  bool SerializeSettings(const SpdySettingsIR& settings,
-                         ZeroCopyOutputBuffer* output) const;
-
-  // Serializes a PING frame. The unique_id is used to
-  // identify the ping request/response.
-  bool SerializePing(const SpdyPingIR& ping,
-                     ZeroCopyOutputBuffer* output) const;
-
-  // Serializes a GOAWAY frame. The GOAWAY frame is used
-  // prior to the shutting down of the TCP connection, and includes the
-  // stream_id of the last stream the sender of the frame is willing to process
-  // to completion.
-  bool SerializeGoAway(const SpdyGoAwayIR& goaway,
-                       ZeroCopyOutputBuffer* output) const;
-
-  // Serializes a HEADERS frame. The HEADERS frame is used
-  // for sending headers.
-  bool SerializeHeaders(const SpdyHeadersIR& headers,
-                        ZeroCopyOutputBuffer* output);
-
-  // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE
-  // frame is used to implement per stream flow control.
-  bool SerializeWindowUpdate(const SpdyWindowUpdateIR& window_update,
-                             ZeroCopyOutputBuffer* output) const;
-
-  // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used
-  // to inform the client that it will be receiving an additional stream
-  // in response to the original request. The frame includes synthesized
-  // headers to explain the upcoming data.
-  bool SerializePushPromise(const SpdyPushPromiseIR& push_promise,
-                            ZeroCopyOutputBuffer* output);
-
-  // Serializes a CONTINUATION frame. The CONTINUATION frame is used
-  // to continue a sequence of header block fragments.
-  bool SerializeContinuation(const SpdyContinuationIR& continuation,
-                             ZeroCopyOutputBuffer* output) const;
-
-  // Serializes an ALTSVC frame. The ALTSVC frame advertises the
-  // availability of an alternative service to the client.
-  bool SerializeAltSvc(const SpdyAltSvcIR& altsvc,
-                       ZeroCopyOutputBuffer* output);
-
-  // Serializes a PRIORITY frame. The PRIORITY frame advises a change in
-  // the relative priority of the given stream.
-  bool SerializePriority(const SpdyPriorityIR& priority,
-                         ZeroCopyOutputBuffer* output) const;
-
-  // Serializes a PRIORITY_UPDATE frame.
-  // See https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html.
-  bool SerializePriorityUpdate(const SpdyPriorityUpdateIR& priority_update,
-                               ZeroCopyOutputBuffer* output) const;
-
-  // Serializes an ACCEPT_CH frame.  See
-  // https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02.
-  bool SerializeAcceptCh(const SpdyAcceptChIR& accept_ch,
-                         ZeroCopyOutputBuffer* output) const;
-
-  // Serializes an unknown frame given a frame header and payload.
-  bool SerializeUnknown(const SpdyUnknownIR& unknown,
-                        ZeroCopyOutputBuffer* output) const;
-
-  // Serialize a frame of unknown type.
-  size_t SerializeFrame(const SpdyFrameIR& frame, ZeroCopyOutputBuffer* output);
-
-  // Returns whether this SpdyFramer will compress header blocks using HPACK.
-  bool compression_enabled() const {
-    return compression_option_ == ENABLE_COMPRESSION;
-  }
-
-  void SetHpackIndexingPolicy(HpackEncoder::IndexingPolicy policy) {
-    GetHpackEncoder()->SetIndexingPolicy(std::move(policy));
-  }
-
-  // Updates the maximum size of the header encoder compression table.
-  void UpdateHeaderEncoderTableSize(uint32_t value);
-
-  // Returns the maximum size of the header encoder compression table.
-  size_t header_encoder_table_size() const;
-
-  // Get (and lazily initialize) the HPACK encoder state.
-  HpackEncoder* GetHpackEncoder();
-
-  // Gets the HPACK encoder state. Returns nullptr if the encoder has not been
-  // initialized.
-  const HpackEncoder* GetHpackEncoder() const { return hpack_encoder_.get(); }
-
- protected:
-  friend class test::SpdyFramerPeer;
-  friend class test::SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
-  friend class test::SpdyFramerTest_PushPromiseFramesWithIterator_Test;
-
-  // Iteratively converts a SpdyFrameIR into an appropriate sequence of Spdy
-  // frames.
-  // Example usage:
-  // std::unique_ptr<SpdyFrameSequence> it = CreateIterator(framer, frame_ir);
-  // while (it->HasNextFrame()) {
-  //   if(it->NextFrame(output) == 0) {
-  //     // Write failed;
-  //   }
-  // }
-  class QUICHE_EXPORT SpdyFrameIterator : public SpdyFrameSequence {
-   public:
-    // Creates an iterator with the provided framer.
-    // Does not take ownership of |framer|.
-    // |framer| must outlive this instance.
-    explicit SpdyFrameIterator(SpdyFramer* framer);
-    ~SpdyFrameIterator() override;
-
-    // Serializes the next frame in the sequence to |output|. Returns the number
-    // of bytes written to |output|.
-    size_t NextFrame(ZeroCopyOutputBuffer* output) override;
-
-    // Returns true iff there is at least one more frame in the sequence.
-    bool HasNextFrame() const override;
-
-    // SpdyFrameIterator is neither copyable nor movable.
-    SpdyFrameIterator(const SpdyFrameIterator&) = delete;
-    SpdyFrameIterator& operator=(const SpdyFrameIterator&) = delete;
-
-   protected:
-    virtual size_t GetFrameSizeSansBlock() const = 0;
-    virtual bool SerializeGivenEncoding(const std::string& encoding,
-                                        ZeroCopyOutputBuffer* output) const = 0;
-
-    SpdyFramer* GetFramer() const { return framer_; }
-
-    void SetEncoder(const SpdyFrameWithHeaderBlockIR* ir) {
-      encoder_ =
-          framer_->GetHpackEncoder()->EncodeHeaderSet(ir->header_block());
-    }
-
-    bool has_next_frame() const { return has_next_frame_; }
-
-   private:
-    SpdyFramer* const framer_;
-    std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoder_;
-    bool is_first_frame_;
-    bool has_next_frame_;
-  };
-
-  // Iteratively converts a SpdyHeadersIR (with a possibly huge
-  // Http2HeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
-  // write to the output.
-  class QUICHE_EXPORT SpdyHeaderFrameIterator : public SpdyFrameIterator {
-   public:
-    // Does not take ownership of |framer|. Take ownership of |headers_ir|.
-    SpdyHeaderFrameIterator(SpdyFramer* framer,
-                            std::unique_ptr<const SpdyHeadersIR> headers_ir);
-
-    ~SpdyHeaderFrameIterator() override;
-
-   private:
-    const SpdyFrameIR& GetIR() const override;
-    size_t GetFrameSizeSansBlock() const override;
-    bool SerializeGivenEncoding(const std::string& encoding,
-                                ZeroCopyOutputBuffer* output) const override;
-
-    const std::unique_ptr<const SpdyHeadersIR> headers_ir_;
-  };
-
-  // Iteratively converts a SpdyPushPromiseIR (with a possibly huge
-  // Http2HeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
-  // write to the output.
-  class QUICHE_EXPORT SpdyPushPromiseFrameIterator : public SpdyFrameIterator {
-   public:
-    // Does not take ownership of |framer|. Take ownership of |push_promise_ir|.
-    SpdyPushPromiseFrameIterator(
-        SpdyFramer* framer,
-        std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir);
-
-    ~SpdyPushPromiseFrameIterator() override;
-
-   private:
-    const SpdyFrameIR& GetIR() const override;
-    size_t GetFrameSizeSansBlock() const override;
-    bool SerializeGivenEncoding(const std::string& encoding,
-                                ZeroCopyOutputBuffer* output) const override;
-
-    const std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir_;
-  };
-
-  // Converts a SpdyFrameIR into one Spdy frame (a sequence of length 1), and
-  // write it to the output.
-  class QUICHE_EXPORT SpdyControlFrameIterator : public SpdyFrameSequence {
-   public:
-    SpdyControlFrameIterator(SpdyFramer* framer,
-                             std::unique_ptr<const SpdyFrameIR> frame_ir);
-    ~SpdyControlFrameIterator() override;
-
-    size_t NextFrame(ZeroCopyOutputBuffer* output) override;
-
-    bool HasNextFrame() const override;
-
-    const SpdyFrameIR& GetIR() const override;
-
-   private:
-    SpdyFramer* const framer_;
-    std::unique_ptr<const SpdyFrameIR> frame_ir_;
-    bool has_next_frame_ = true;
-  };
-
- private:
-  void SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers,
-                                     uint8_t* flags, size_t* size,
-                                     std::string* hpack_encoding, int* weight,
-                                     size_t* length_field);
-  void SerializePushPromiseBuilderHelper(const SpdyPushPromiseIR& push_promise,
-                                         uint8_t* flags,
-                                         std::string* hpack_encoding,
-                                         size_t* size);
-
-  std::unique_ptr<HpackEncoder> hpack_encoder_;
-
-  SpdyFramerDebugVisitorInterface* debug_visitor_;
-
-  // Determines whether HPACK compression is used.
-  const CompressionOption compression_option_;
-};
-
-}  // namespace spdy
+#include "quiche/http2/core/spdy_framer.h"
 
 #endif  // QUICHE_SPDY_CORE_SPDY_FRAMER_H_
diff --git a/quiche/spdy/core/spdy_protocol.h b/quiche/spdy/core/spdy_protocol.h
index ec57be2..fbc7499 100644
--- a/quiche/spdy/core/spdy_protocol.h
+++ b/quiche/spdy/core/spdy_protocol.h
@@ -2,1100 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This file contains some protocol structures for use with SPDY 3 and HTTP 2
-// The SPDY 3 spec can be found at:
-// http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3
-
 #ifndef QUICHE_SPDY_CORE_SPDY_PROTOCOL_H_
 #define QUICHE_SPDY_CORE_SPDY_PROTOCOL_H_
 
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <iosfwd>
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "absl/strings/string_view.h"
-#include "absl/types/variant.h"
-#include "quiche/common/platform/api/quiche_export.h"
-#include "quiche/common/platform/api/quiche_flags.h"
-#include "quiche/common/platform/api/quiche_logging.h"
-#include "quiche/spdy/core/http2_header_block.h"
-#include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
-#include "quiche/spdy/core/spdy_bitmasks.h"
-
-namespace spdy {
-
-// A stream ID is a 31-bit entity.
-using SpdyStreamId = uint32_t;
-
-// A SETTINGS ID is a 16-bit entity.
-using SpdySettingsId = uint16_t;
-
-// Specifies the stream ID used to denote the current session (for
-// flow control).
-inline constexpr SpdyStreamId kSessionFlowControlStreamId = 0;
-
-// 0 is not a valid stream ID for any other purpose than flow control.
-inline constexpr SpdyStreamId kInvalidStreamId = 0;
-
-// Max stream id.
-inline constexpr SpdyStreamId kMaxStreamId = 0x7fffffff;
-
-// The maximum possible frame payload size allowed by the spec.
-inline constexpr uint32_t kSpdyMaxFrameSizeLimit = (1 << 24) - 1;
-
-// The initial value for the maximum frame payload size as per the spec. This is
-// the maximum control frame size we accept.
-inline constexpr uint32_t kHttp2DefaultFramePayloadLimit = 1 << 14;
-
-// The maximum size of the control frames that we send, including the size of
-// the header. This limit is arbitrary. We can enforce it here or at the
-// application layer. We chose the framing layer, but this can be changed (or
-// removed) if necessary later down the line.
-inline constexpr size_t kHttp2MaxControlFrameSendSize =
-    kHttp2DefaultFramePayloadLimit - 1;
-
-// Number of octets in the frame header.
-inline constexpr size_t kFrameHeaderSize = 9;
-
-// The initial value for the maximum frame payload size as per the spec. This is
-// the maximum control frame size we accept.
-inline constexpr uint32_t kHttp2DefaultFrameSizeLimit =
-    kHttp2DefaultFramePayloadLimit + kFrameHeaderSize;
-
-// The initial value for the maximum size of the header list, "unlimited" (max
-// unsigned 32-bit int) as per the spec.
-inline constexpr uint32_t kSpdyInitialHeaderListSizeLimit = 0xFFFFFFFF;
-
-// Maximum window size for a Spdy stream or session.
-inline constexpr int32_t kSpdyMaximumWindowSize =
-    0x7FFFFFFF;  // Max signed 32bit int
-
-// Maximum padding size in octets for one DATA or HEADERS or PUSH_PROMISE frame.
-inline constexpr int32_t kPaddingSizePerFrame = 256;
-
-// The HTTP/2 connection preface, which must be the first bytes sent by the
-// client upon starting an HTTP/2 connection, and which must be followed by a
-// SETTINGS frame.  Note that even though |kHttp2ConnectionHeaderPrefix| is
-// defined as a string literal with a null terminator, the actual connection
-// preface is only the first |kHttp2ConnectionHeaderPrefixSize| bytes, which
-// excludes the null terminator.
-QUICHE_EXPORT extern const char* const kHttp2ConnectionHeaderPrefix;
-inline constexpr int kHttp2ConnectionHeaderPrefixSize = 24;
-
-// Wire values for HTTP2 frame types.
-enum class SpdyFrameType : uint8_t {
-  DATA = 0x00,
-  HEADERS = 0x01,
-  PRIORITY = 0x02,
-  RST_STREAM = 0x03,
-  SETTINGS = 0x04,
-  PUSH_PROMISE = 0x05,
-  PING = 0x06,
-  GOAWAY = 0x07,
-  WINDOW_UPDATE = 0x08,
-  CONTINUATION = 0x09,
-  // ALTSVC is a public extension.
-  ALTSVC = 0x0a,
-  PRIORITY_UPDATE = 0x10,
-  ACCEPT_CH = 0x89,
-};
-
-// Flags on data packets.
-enum SpdyDataFlags {
-  DATA_FLAG_NONE = 0x00,
-  DATA_FLAG_FIN = 0x01,
-  DATA_FLAG_PADDED = 0x08,
-};
-
-// Flags on control packets
-enum SpdyControlFlags {
-  CONTROL_FLAG_NONE = 0x00,
-  CONTROL_FLAG_FIN = 0x01,
-};
-
-enum SpdyPingFlags {
-  PING_FLAG_ACK = 0x01,
-};
-
-// Used by HEADERS, PUSH_PROMISE, and CONTINUATION.
-enum SpdyHeadersFlags {
-  HEADERS_FLAG_END_HEADERS = 0x04,
-  HEADERS_FLAG_PADDED = 0x08,
-  HEADERS_FLAG_PRIORITY = 0x20,
-};
-
-enum SpdyPushPromiseFlags {
-  PUSH_PROMISE_FLAG_END_PUSH_PROMISE = 0x04,
-  PUSH_PROMISE_FLAG_PADDED = 0x08,
-};
-
-enum Http2SettingsControlFlags {
-  SETTINGS_FLAG_ACK = 0x01,
-};
-
-// Wire values of HTTP/2 setting identifiers.
-enum SpdyKnownSettingsId : SpdySettingsId {
-  // HPACK header table maximum size.
-  SETTINGS_HEADER_TABLE_SIZE = 0x1,
-  SETTINGS_MIN = SETTINGS_HEADER_TABLE_SIZE,
-  // Whether or not server push (PUSH_PROMISE) is enabled.
-  SETTINGS_ENABLE_PUSH = 0x2,
-  // The maximum number of simultaneous live streams in each direction.
-  SETTINGS_MAX_CONCURRENT_STREAMS = 0x3,
-  // Initial window size in bytes
-  SETTINGS_INITIAL_WINDOW_SIZE = 0x4,
-  // The size of the largest frame payload that a receiver is willing to accept.
-  SETTINGS_MAX_FRAME_SIZE = 0x5,
-  // The maximum size of header list that the sender is prepared to accept.
-  SETTINGS_MAX_HEADER_LIST_SIZE = 0x6,
-  // Enable Websockets over HTTP/2, see
-  // https://httpwg.org/specs/rfc8441.html
-  SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x8,
-  // Disable HTTP/2 priorities, see
-  // https://tools.ietf.org/html/draft-ietf-httpbis-priority-02.
-  SETTINGS_DEPRECATE_HTTP2_PRIORITIES = 0x9,
-  SETTINGS_MAX = SETTINGS_DEPRECATE_HTTP2_PRIORITIES,
-  // Experimental setting used to configure an alternative write scheduler.
-  SETTINGS_EXPERIMENT_SCHEDULER = 0xFF45,
-};
-
-// This explicit operator is needed, otherwise compiler finds
-// overloaded operator to be ambiguous.
-QUICHE_EXPORT std::ostream& operator<<(std::ostream& out,
-                                       SpdyKnownSettingsId id);
-
-// This operator is needed, because SpdyFrameType is an enum class,
-// therefore implicit conversion to underlying integer type is not allowed.
-QUICHE_EXPORT std::ostream& operator<<(std::ostream& out,
-                                       SpdyFrameType frame_type);
-
-using SettingsMap = std::map<SpdySettingsId, uint32_t>;
-
-// HTTP/2 error codes, RFC 7540 Section 7.
-enum SpdyErrorCode : uint32_t {
-  ERROR_CODE_NO_ERROR = 0x0,
-  ERROR_CODE_PROTOCOL_ERROR = 0x1,
-  ERROR_CODE_INTERNAL_ERROR = 0x2,
-  ERROR_CODE_FLOW_CONTROL_ERROR = 0x3,
-  ERROR_CODE_SETTINGS_TIMEOUT = 0x4,
-  ERROR_CODE_STREAM_CLOSED = 0x5,
-  ERROR_CODE_FRAME_SIZE_ERROR = 0x6,
-  ERROR_CODE_REFUSED_STREAM = 0x7,
-  ERROR_CODE_CANCEL = 0x8,
-  ERROR_CODE_COMPRESSION_ERROR = 0x9,
-  ERROR_CODE_CONNECT_ERROR = 0xa,
-  ERROR_CODE_ENHANCE_YOUR_CALM = 0xb,
-  ERROR_CODE_INADEQUATE_SECURITY = 0xc,
-  ERROR_CODE_HTTP_1_1_REQUIRED = 0xd,
-  ERROR_CODE_MAX = ERROR_CODE_HTTP_1_1_REQUIRED
-};
-
-// Type of priority write scheduler.
-enum class WriteSchedulerType {
-  LIFO,  // Last added stream has the highest priority.
-  SPDY,  // Uses SPDY priorities described in
-         // https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1#TOC-2.3.3-Stream-priority.
-  HTTP2,  // Uses HTTP2 (tree-style) priority described in
-          // https://tools.ietf.org/html/rfc7540#section-5.3.
-  FIFO,   // Stream with the smallest stream ID has the highest priority.
-};
-
-// A SPDY priority is a number between 0 and 7 (inclusive).
-typedef uint8_t SpdyPriority;
-
-// Lowest and Highest here refer to SPDY priorities as described in
-// https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1#TOC-2.3.3-Stream-priority
-inline constexpr SpdyPriority kV3HighestPriority = 0;
-inline constexpr SpdyPriority kV3LowestPriority = 7;
-
-// Returns SPDY 3.x priority value clamped to the valid range of [0, 7].
-QUICHE_EXPORT SpdyPriority ClampSpdy3Priority(SpdyPriority priority);
-
-// HTTP/2 stream weights are integers in range [1, 256], as specified in RFC
-// 7540 section 5.3.2. Default stream weight is defined in section 5.3.5.
-inline constexpr int kHttp2MinStreamWeight = 1;
-inline constexpr int kHttp2MaxStreamWeight = 256;
-inline constexpr int kHttp2DefaultStreamWeight = 16;
-
-// Returns HTTP/2 weight clamped to the valid range of [1, 256].
-QUICHE_EXPORT int ClampHttp2Weight(int weight);
-
-// Maps SPDY 3.x priority value in range [0, 7] to HTTP/2 weight value in range
-// [1, 256], where priority 0 (i.e. highest precedence) corresponds to maximum
-// weight 256 and priority 7 (lowest precedence) corresponds to minimum weight
-// 1.
-QUICHE_EXPORT int Spdy3PriorityToHttp2Weight(SpdyPriority priority);
-
-// Maps HTTP/2 weight value in range [1, 256] to SPDY 3.x priority value in
-// range [0, 7], where minimum weight 1 corresponds to priority 7 (lowest
-// precedence) and maximum weight 256 corresponds to priority 0 (highest
-// precedence).
-QUICHE_EXPORT SpdyPriority Http2WeightToSpdy3Priority(int weight);
-
-// Reserved ID for root stream of HTTP/2 stream dependency tree, as specified
-// in RFC 7540 section 5.3.1.
-const unsigned int kHttp2RootStreamId = 0;
-
-typedef uint64_t SpdyPingId;
-
-// Returns true if a given on-the-wire enumeration of a frame type is defined
-// in a standardized HTTP/2 specification, false otherwise.
-QUICHE_EXPORT bool IsDefinedFrameType(uint8_t frame_type_field);
-
-// Parses a frame type from an on-the-wire enumeration.
-// Behavior is undefined for invalid frame type fields; consumers should first
-// use IsValidFrameType() to verify validity of frame type fields.
-QUICHE_EXPORT SpdyFrameType ParseFrameType(uint8_t frame_type_field);
-
-// Serializes a frame type to the on-the-wire value.
-QUICHE_EXPORT uint8_t SerializeFrameType(SpdyFrameType frame_type);
-
-// (HTTP/2) All standard frame types except WINDOW_UPDATE are
-// (stream-specific xor connection-level). Returns false iff we know
-// the given frame type does not align with the given streamID.
-QUICHE_EXPORT bool IsValidHTTP2FrameStreamId(
-    SpdyStreamId current_frame_stream_id, SpdyFrameType frame_type_field);
-
-// Serialize |frame_type| to string for logging/debugging.
-QUICHE_EXPORT const char* FrameTypeToString(SpdyFrameType frame_type);
-
-// If |wire_setting_id| is the on-the-wire representation of a defined SETTINGS
-// parameter, parse it to |*setting_id| and return true.
-QUICHE_EXPORT bool ParseSettingsId(SpdySettingsId wire_setting_id,
-                                   SpdyKnownSettingsId* setting_id);
-
-// Returns a string representation of the |id| for logging/debugging. Returns
-// the |id| prefixed with "SETTINGS_UNKNOWN_" for unknown SETTINGS IDs. To parse
-// the |id| into a SpdyKnownSettingsId (if applicable), use ParseSettingsId().
-QUICHE_EXPORT std::string SettingsIdToString(SpdySettingsId id);
-
-// Parse |wire_error_code| to a SpdyErrorCode.
-// Treat unrecognized error codes as INTERNAL_ERROR
-// as recommended by the HTTP/2 specification.
-QUICHE_EXPORT SpdyErrorCode ParseErrorCode(uint32_t wire_error_code);
-
-// Serialize RST_STREAM or GOAWAY frame error code to string
-// for logging/debugging.
-QUICHE_EXPORT const char* ErrorCodeToString(SpdyErrorCode error_code);
-
-// Serialize |type| to string for logging/debugging.
-QUICHE_EXPORT const char* WriteSchedulerTypeToString(WriteSchedulerType type);
-
-// Minimum size of a frame, in octets.
-inline constexpr size_t kFrameMinimumSize = kFrameHeaderSize;
-
-// Minimum frame size for variable size frame types (includes mandatory fields),
-// frame size for fixed size frames, in octets.
-
-inline constexpr size_t kDataFrameMinimumSize = kFrameHeaderSize;
-inline constexpr size_t kHeadersFrameMinimumSize = kFrameHeaderSize;
-// PRIORITY frame has stream_dependency (4 octets) and weight (1 octet) fields.
-inline constexpr size_t kPriorityFrameSize = kFrameHeaderSize + 5;
-// RST_STREAM frame has error_code (4 octets) field.
-inline constexpr size_t kRstStreamFrameSize = kFrameHeaderSize + 4;
-inline constexpr size_t kSettingsFrameMinimumSize = kFrameHeaderSize;
-inline constexpr size_t kSettingsOneSettingSize =
-    sizeof(uint32_t) + sizeof(SpdySettingsId);
-// PUSH_PROMISE frame has promised_stream_id (4 octet) field.
-inline constexpr size_t kPushPromiseFrameMinimumSize = kFrameHeaderSize + 4;
-// PING frame has opaque_bytes (8 octet) field.
-inline constexpr size_t kPingFrameSize = kFrameHeaderSize + 8;
-// GOAWAY frame has last_stream_id (4 octet) and error_code (4 octet) fields.
-inline constexpr size_t kGoawayFrameMinimumSize = kFrameHeaderSize + 8;
-// WINDOW_UPDATE frame has window_size_increment (4 octet) field.
-inline constexpr size_t kWindowUpdateFrameSize = kFrameHeaderSize + 4;
-inline constexpr size_t kContinuationFrameMinimumSize = kFrameHeaderSize;
-// ALTSVC frame has origin_len (2 octets) field.
-inline constexpr size_t kGetAltSvcFrameMinimumSize = kFrameHeaderSize + 2;
-// PRIORITY_UPDATE frame has prioritized_stream_id (4 octets) field.
-inline constexpr size_t kPriorityUpdateFrameMinimumSize = kFrameHeaderSize + 4;
-// ACCEPT_CH frame may have empty payload.
-inline constexpr size_t kAcceptChFrameMinimumSize = kFrameHeaderSize;
-// Each ACCEPT_CH frame entry has a 16-bit origin length and a 16-bit value
-// length.
-inline constexpr size_t kAcceptChFramePerEntryOverhead = 4;
-
-// Maximum possible configurable size of a frame in octets.
-inline constexpr size_t kMaxFrameSizeLimit =
-    kSpdyMaxFrameSizeLimit + kFrameHeaderSize;
-// Size of a header block size field.
-inline constexpr size_t kSizeOfSizeField = sizeof(uint32_t);
-// Initial window size for a stream in bytes.
-inline constexpr int32_t kInitialStreamWindowSize = 64 * 1024 - 1;
-// Initial window size for a session in bytes.
-inline constexpr int32_t kInitialSessionWindowSize = 64 * 1024 - 1;
-// The NPN string for HTTP2, "h2".
-QUICHE_EXPORT extern const char* const kHttp2Npn;
-// An estimate of the HPACK overhead for each header field in bytes, intended to
-// be no smaller than actual overhead, based on the literal header field
-// representation in RFC 7541 Section 6.2 (with or without indexing):
-//   - 1 byte for the opcode.
-//   - 2 bytes for the name length (assuming new name).
-//   - 3 bytes for the value length.
-// TODO(b/322146543): Remove the `New` suffix with deprecation of
-// --gfe2_reloadable_flag_http2_add_hpack_overhead_bytes2.
-inline constexpr size_t kPerHeaderHpackOverheadNew = 6;
-// An estimate size of the HPACK overhead for each header field. 1 bytes for
-// indexed literal, 1 bytes for key literal and length encoding, and 2 bytes for
-// value literal and length encoding.
-// TODO(b/322146543): Remove with deprecation of
-// --gfe2_reloadable_flag_http2_add_hpack_overhead_bytes2.
-inline constexpr size_t kPerHeaderHpackOverheadOld = 4;
-
-// Names of pseudo-headers defined for HTTP/2 requests.
-QUICHE_EXPORT extern const char* const kHttp2AuthorityHeader;
-QUICHE_EXPORT extern const char* const kHttp2MethodHeader;
-QUICHE_EXPORT extern const char* const kHttp2PathHeader;
-QUICHE_EXPORT extern const char* const kHttp2SchemeHeader;
-QUICHE_EXPORT extern const char* const kHttp2ProtocolHeader;
-
-// Name of pseudo-header defined for HTTP/2 responses.
-QUICHE_EXPORT extern const char* const kHttp2StatusHeader;
-
-QUICHE_EXPORT size_t GetNumberRequiredContinuationFrames(size_t size);
-
-// Variant type that is either a SPDY 3.x priority value, or else an HTTP/2
-// stream dependency tuple {parent stream ID, weight, exclusive bit}. Templated
-// to allow for use by QUIC code; SPDY and HTTP/2 code should use the concrete
-// type instantiation SpdyStreamPrecedence.
-template <typename StreamIdType>
-class QUICHE_EXPORT StreamPrecedence {
- public:
-  // Constructs instance that is a SPDY 3.x priority. Clamps priority value to
-  // the valid range [0, 7].
-  explicit StreamPrecedence(SpdyPriority priority)
-      : precedence_(ClampSpdy3Priority(priority)) {}
-
-  // Constructs instance that is an HTTP/2 stream weight, parent stream ID, and
-  // exclusive bit. Clamps stream weight to the valid range [1, 256].
-  StreamPrecedence(StreamIdType parent_id, int weight, bool is_exclusive)
-      : precedence_(Http2StreamDependency{parent_id, ClampHttp2Weight(weight),
-                                          is_exclusive}) {}
-
-  // Intentionally copyable, to support pass by value.
-  StreamPrecedence(const StreamPrecedence& other) = default;
-  StreamPrecedence& operator=(const StreamPrecedence& other) = default;
-
-  // Returns true if this instance is a SPDY 3.x priority, or false if this
-  // instance is an HTTP/2 stream dependency.
-  bool is_spdy3_priority() const {
-    return absl::holds_alternative<SpdyPriority>(precedence_);
-  }
-
-  // Returns SPDY 3.x priority value. If |is_spdy3_priority()| is true, this is
-  // the value provided at construction, clamped to the legal priority
-  // range. Otherwise, it is the HTTP/2 stream weight mapped to a SPDY 3.x
-  // priority value, where minimum weight 1 corresponds to priority 7 (lowest
-  // precedence) and maximum weight 256 corresponds to priority 0 (highest
-  // precedence).
-  SpdyPriority spdy3_priority() const {
-    return is_spdy3_priority()
-               ? absl::get<SpdyPriority>(precedence_)
-               : Http2WeightToSpdy3Priority(
-                     absl::get<Http2StreamDependency>(precedence_).weight);
-  }
-
-  // Returns HTTP/2 parent stream ID. If |is_spdy3_priority()| is false, this is
-  // the value provided at construction, otherwise it is |kHttp2RootStreamId|.
-  StreamIdType parent_id() const {
-    return is_spdy3_priority()
-               ? kHttp2RootStreamId
-               : absl::get<Http2StreamDependency>(precedence_).parent_id;
-  }
-
-  // Returns HTTP/2 stream weight. If |is_spdy3_priority()| is false, this is
-  // the value provided at construction, clamped to the legal weight
-  // range. Otherwise, it is the SPDY 3.x priority value mapped to an HTTP/2
-  // stream weight, where priority 0 (i.e. highest precedence) corresponds to
-  // maximum weight 256 and priority 7 (lowest precedence) corresponds to
-  // minimum weight 1.
-  int weight() const {
-    return is_spdy3_priority()
-               ? Spdy3PriorityToHttp2Weight(
-                     absl::get<SpdyPriority>(precedence_))
-               : absl::get<Http2StreamDependency>(precedence_).weight;
-  }
-
-  // Returns HTTP/2 parent stream exclusivity. If |is_spdy3_priority()| is
-  // false, this is the value provided at construction, otherwise it is false.
-  bool is_exclusive() const {
-    return absl::holds_alternative<Http2StreamDependency>(precedence_) &&
-           absl::get<Http2StreamDependency>(precedence_).is_exclusive;
-  }
-
-  // Facilitates test assertions.
-  bool operator==(const StreamPrecedence& other) const {
-    return precedence_ == other.precedence_;
-  }
-
-  bool operator!=(const StreamPrecedence& other) const {
-    return !(*this == other);
-  }
-
- private:
-  struct QUICHE_EXPORT Http2StreamDependency {
-    StreamIdType parent_id;
-    int weight;
-    bool is_exclusive;
-
-    bool operator==(const Http2StreamDependency& other) const {
-      return parent_id == other.parent_id && weight == other.weight &&
-             is_exclusive == other.is_exclusive;
-    }
-  };
-
-  absl::variant<SpdyPriority, Http2StreamDependency> precedence_;
-};
-
-typedef StreamPrecedence<SpdyStreamId> SpdyStreamPrecedence;
-
-class SpdyFrameVisitor;
-
-// Intermediate representation for HTTP2 frames.
-class QUICHE_EXPORT SpdyFrameIR {
- public:
-  virtual ~SpdyFrameIR() {}
-
-  virtual void Visit(SpdyFrameVisitor* visitor) const = 0;
-  virtual SpdyFrameType frame_type() const = 0;
-  SpdyStreamId stream_id() const { return stream_id_; }
-  virtual bool fin() const;
-  // Returns an estimate of the size of the serialized frame, without applying
-  // compression. May not be exact, but implementations should return the same
-  // value for a const frame.
-  virtual size_t size() const = 0;
-
-  // Returns the number of bytes of flow control window that would be consumed
-  // by this frame if written to the wire.
-  virtual int flow_control_window_consumed() const;
-
- protected:
-  SpdyFrameIR() : stream_id_(0) {}
-  explicit SpdyFrameIR(SpdyStreamId stream_id) : stream_id_(stream_id) {}
-  SpdyFrameIR(const SpdyFrameIR&) = delete;
-  SpdyFrameIR& operator=(const SpdyFrameIR&) = delete;
-
- private:
-  SpdyStreamId stream_id_;
-};
-
-// Abstract class intended to be inherited by IRs that have the option of a FIN
-// flag.
-class QUICHE_EXPORT SpdyFrameWithFinIR : public SpdyFrameIR {
- public:
-  ~SpdyFrameWithFinIR() override {}
-  bool fin() const override;
-  void set_fin(bool fin) { fin_ = fin; }
-
- protected:
-  explicit SpdyFrameWithFinIR(SpdyStreamId stream_id)
-      : SpdyFrameIR(stream_id), fin_(false) {}
-  SpdyFrameWithFinIR(const SpdyFrameWithFinIR&) = delete;
-  SpdyFrameWithFinIR& operator=(const SpdyFrameWithFinIR&) = delete;
-
- private:
-  bool fin_;
-};
-
-// Abstract class intended to be inherited by IRs that contain a header
-// block. Implies SpdyFrameWithFinIR.
-class QUICHE_EXPORT SpdyFrameWithHeaderBlockIR : public SpdyFrameWithFinIR {
- public:
-  ~SpdyFrameWithHeaderBlockIR() override;
-
-  const Http2HeaderBlock& header_block() const { return header_block_; }
-  void set_header_block(Http2HeaderBlock header_block) {
-    // Deep copy.
-    header_block_ = std::move(header_block);
-  }
-  void SetHeader(absl::string_view name, absl::string_view value) {
-    header_block_[name] = value;
-  }
-
- protected:
-  SpdyFrameWithHeaderBlockIR(SpdyStreamId stream_id,
-                             Http2HeaderBlock header_block);
-  SpdyFrameWithHeaderBlockIR(const SpdyFrameWithHeaderBlockIR&) = delete;
-  SpdyFrameWithHeaderBlockIR& operator=(const SpdyFrameWithHeaderBlockIR&) =
-      delete;
-
- private:
-  Http2HeaderBlock header_block_;
-};
-
-class QUICHE_EXPORT SpdyDataIR : public SpdyFrameWithFinIR {
- public:
-  // Performs a deep copy on data.
-  SpdyDataIR(SpdyStreamId stream_id, absl::string_view data);
-
-  // Performs a deep copy on data.
-  SpdyDataIR(SpdyStreamId stream_id, const char* data);
-
-  // Moves data into data_store_. Makes a copy if passed a non-movable string.
-  SpdyDataIR(SpdyStreamId stream_id, std::string data);
-
-  // Use in conjunction with SetDataShallow() for shallow-copy on data.
-  explicit SpdyDataIR(SpdyStreamId stream_id);
-  SpdyDataIR(const SpdyDataIR&) = delete;
-  SpdyDataIR& operator=(const SpdyDataIR&) = delete;
-
-  ~SpdyDataIR() override;
-
-  const char* data() const { return data_; }
-  size_t data_len() const { return data_len_; }
-
-  bool padded() const { return padded_; }
-
-  int padding_payload_len() const { return padding_payload_len_; }
-
-  void set_padding_len(int padding_len) {
-    QUICHE_DCHECK_GT(padding_len, 0);
-    QUICHE_DCHECK_LE(padding_len, kPaddingSizePerFrame);
-    padded_ = true;
-    // The pad field takes one octet on the wire.
-    padding_payload_len_ = padding_len - 1;
-  }
-
-  // Deep-copy of data (keep private copy).
-  void SetDataDeep(absl::string_view data) {
-    data_store_ = std::make_unique<std::string>(data.data(), data.size());
-    data_ = data_store_->data();
-    data_len_ = data.size();
-  }
-
-  // Shallow-copy of data (do not keep private copy).
-  void SetDataShallow(absl::string_view data) {
-    data_store_.reset();
-    data_ = data.data();
-    data_len_ = data.size();
-  }
-
-  // Use this method if we don't have a contiguous buffer and only
-  // need a length.
-  void SetDataShallow(size_t len) {
-    data_store_.reset();
-    data_ = nullptr;
-    data_len_ = len;
-  }
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  int flow_control_window_consumed() const override;
-
-  size_t size() const override;
-
- private:
-  // Used to store data that this SpdyDataIR should own.
-  std::unique_ptr<std::string> data_store_;
-  const char* data_;
-  size_t data_len_;
-
-  bool padded_;
-  // padding_payload_len_ = desired padding length - len(padding length field).
-  int padding_payload_len_;
-};
-
-class QUICHE_EXPORT SpdyRstStreamIR : public SpdyFrameIR {
- public:
-  SpdyRstStreamIR(SpdyStreamId stream_id, SpdyErrorCode error_code);
-  SpdyRstStreamIR(const SpdyRstStreamIR&) = delete;
-  SpdyRstStreamIR& operator=(const SpdyRstStreamIR&) = delete;
-
-  ~SpdyRstStreamIR() override;
-
-  SpdyErrorCode error_code() const { return error_code_; }
-  void set_error_code(SpdyErrorCode error_code) { error_code_ = error_code; }
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  size_t size() const override;
-
- private:
-  SpdyErrorCode error_code_;
-};
-
-class QUICHE_EXPORT SpdySettingsIR : public SpdyFrameIR {
- public:
-  SpdySettingsIR();
-  SpdySettingsIR(const SpdySettingsIR&) = delete;
-  SpdySettingsIR& operator=(const SpdySettingsIR&) = delete;
-  ~SpdySettingsIR() override;
-
-  // Overwrites as appropriate.
-  const SettingsMap& values() const { return values_; }
-  void AddSetting(SpdySettingsId id, int32_t value) { values_[id] = value; }
-
-  bool is_ack() const { return is_ack_; }
-  void set_is_ack(bool is_ack) { is_ack_ = is_ack; }
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  size_t size() const override;
-
- private:
-  SettingsMap values_;
-  bool is_ack_;
-};
-
-class QUICHE_EXPORT SpdyPingIR : public SpdyFrameIR {
- public:
-  explicit SpdyPingIR(SpdyPingId id) : id_(id), is_ack_(false) {}
-  SpdyPingIR(const SpdyPingIR&) = delete;
-  SpdyPingIR& operator=(const SpdyPingIR&) = delete;
-  SpdyPingId id() const { return id_; }
-
-  bool is_ack() const { return is_ack_; }
-  void set_is_ack(bool is_ack) { is_ack_ = is_ack; }
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  size_t size() const override;
-
- private:
-  SpdyPingId id_;
-  bool is_ack_;
-};
-
-class QUICHE_EXPORT SpdyGoAwayIR : public SpdyFrameIR {
- public:
-  // References description, doesn't copy it, so description must outlast
-  // this SpdyGoAwayIR.
-  SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyErrorCode error_code,
-               absl::string_view description);
-
-  // References description, doesn't copy it, so description must outlast
-  // this SpdyGoAwayIR.
-  SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyErrorCode error_code,
-               const char* description);
-
-  // Moves description into description_store_, so caller doesn't need to
-  // keep description live after constructing this SpdyGoAwayIR.
-  SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyErrorCode error_code,
-               std::string description);
-  SpdyGoAwayIR(const SpdyGoAwayIR&) = delete;
-  SpdyGoAwayIR& operator=(const SpdyGoAwayIR&) = delete;
-
-  ~SpdyGoAwayIR() override;
-
-  SpdyStreamId last_good_stream_id() const { return last_good_stream_id_; }
-  void set_last_good_stream_id(SpdyStreamId last_good_stream_id) {
-    QUICHE_DCHECK_EQ(0u, last_good_stream_id & ~kStreamIdMask);
-    last_good_stream_id_ = last_good_stream_id;
-  }
-  SpdyErrorCode error_code() const { return error_code_; }
-  void set_error_code(SpdyErrorCode error_code) {
-    // TODO(hkhalil): Check valid ranges of error_code?
-    error_code_ = error_code;
-  }
-
-  const absl::string_view& description() const { return description_; }
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  size_t size() const override;
-
- private:
-  SpdyStreamId last_good_stream_id_;
-  SpdyErrorCode error_code_;
-  const std::string description_store_;
-  const absl::string_view description_;
-};
-
-class QUICHE_EXPORT SpdyHeadersIR : public SpdyFrameWithHeaderBlockIR {
- public:
-  explicit SpdyHeadersIR(SpdyStreamId stream_id)
-      : SpdyHeadersIR(stream_id, Http2HeaderBlock()) {}
-  SpdyHeadersIR(SpdyStreamId stream_id, Http2HeaderBlock header_block)
-      : SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)) {}
-  SpdyHeadersIR(const SpdyHeadersIR&) = delete;
-  SpdyHeadersIR& operator=(const SpdyHeadersIR&) = delete;
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  size_t size() const override;
-
-  bool has_priority() const { return has_priority_; }
-  void set_has_priority(bool has_priority) { has_priority_ = has_priority; }
-  int weight() const { return weight_; }
-  void set_weight(int weight) { weight_ = weight; }
-  SpdyStreamId parent_stream_id() const { return parent_stream_id_; }
-  void set_parent_stream_id(SpdyStreamId id) { parent_stream_id_ = id; }
-  bool exclusive() const { return exclusive_; }
-  void set_exclusive(bool exclusive) { exclusive_ = exclusive; }
-  bool padded() const { return padded_; }
-  int padding_payload_len() const { return padding_payload_len_; }
-  void set_padding_len(int padding_len) {
-    QUICHE_DCHECK_GT(padding_len, 0);
-    QUICHE_DCHECK_LE(padding_len, kPaddingSizePerFrame);
-    padded_ = true;
-    // The pad field takes one octet on the wire.
-    padding_payload_len_ = padding_len - 1;
-  }
-
- private:
-  bool has_priority_ = false;
-  int weight_ = kHttp2DefaultStreamWeight;
-  SpdyStreamId parent_stream_id_ = 0;
-  bool exclusive_ = false;
-  bool padded_ = false;
-  int padding_payload_len_ = 0;
-  const bool add_hpack_overhead_bytes_ =
-      GetQuicheReloadableFlag(http2_add_hpack_overhead_bytes2);
-};
-
-class QUICHE_EXPORT SpdyWindowUpdateIR : public SpdyFrameIR {
- public:
-  SpdyWindowUpdateIR(SpdyStreamId stream_id, int32_t delta)
-      : SpdyFrameIR(stream_id) {
-    set_delta(delta);
-  }
-  SpdyWindowUpdateIR(const SpdyWindowUpdateIR&) = delete;
-  SpdyWindowUpdateIR& operator=(const SpdyWindowUpdateIR&) = delete;
-
-  int32_t delta() const { return delta_; }
-  void set_delta(int32_t delta) {
-    QUICHE_DCHECK_LE(0, delta);
-    QUICHE_DCHECK_LE(delta, kSpdyMaximumWindowSize);
-    delta_ = delta;
-  }
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  size_t size() const override;
-
- private:
-  int32_t delta_;
-};
-
-class QUICHE_EXPORT SpdyPushPromiseIR : public SpdyFrameWithHeaderBlockIR {
- public:
-  SpdyPushPromiseIR(SpdyStreamId stream_id, SpdyStreamId promised_stream_id)
-      : SpdyPushPromiseIR(stream_id, promised_stream_id, Http2HeaderBlock()) {}
-  SpdyPushPromiseIR(SpdyStreamId stream_id, SpdyStreamId promised_stream_id,
-                    Http2HeaderBlock header_block)
-      : SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)),
-        promised_stream_id_(promised_stream_id),
-        padded_(false),
-        padding_payload_len_(0) {}
-  SpdyPushPromiseIR(const SpdyPushPromiseIR&) = delete;
-  SpdyPushPromiseIR& operator=(const SpdyPushPromiseIR&) = delete;
-  SpdyStreamId promised_stream_id() const { return promised_stream_id_; }
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  size_t size() const override;
-
-  bool padded() const { return padded_; }
-  int padding_payload_len() const { return padding_payload_len_; }
-  void set_padding_len(int padding_len) {
-    QUICHE_DCHECK_GT(padding_len, 0);
-    QUICHE_DCHECK_LE(padding_len, kPaddingSizePerFrame);
-    padded_ = true;
-    // The pad field takes one octet on the wire.
-    padding_payload_len_ = padding_len - 1;
-  }
-
- private:
-  SpdyStreamId promised_stream_id_;
-
-  bool padded_;
-  int padding_payload_len_;
-};
-
-class QUICHE_EXPORT SpdyContinuationIR : public SpdyFrameIR {
- public:
-  explicit SpdyContinuationIR(SpdyStreamId stream_id);
-  SpdyContinuationIR(const SpdyContinuationIR&) = delete;
-  SpdyContinuationIR& operator=(const SpdyContinuationIR&) = delete;
-  ~SpdyContinuationIR() override;
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  bool end_headers() const { return end_headers_; }
-  void set_end_headers(bool end_headers) { end_headers_ = end_headers; }
-  const std::string& encoding() const { return encoding_; }
-  void take_encoding(std::string encoding) { encoding_ = std::move(encoding); }
-  size_t size() const override;
-
- private:
-  std::string encoding_;
-  bool end_headers_;
-};
-
-class QUICHE_EXPORT SpdyAltSvcIR : public SpdyFrameIR {
- public:
-  explicit SpdyAltSvcIR(SpdyStreamId stream_id);
-  SpdyAltSvcIR(const SpdyAltSvcIR&) = delete;
-  SpdyAltSvcIR& operator=(const SpdyAltSvcIR&) = delete;
-  ~SpdyAltSvcIR() override;
-
-  std::string origin() const { return origin_; }
-  const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector() const {
-    return altsvc_vector_;
-  }
-
-  void set_origin(std::string origin) { origin_ = std::move(origin); }
-  void add_altsvc(const SpdyAltSvcWireFormat::AlternativeService& altsvc) {
-    altsvc_vector_.push_back(altsvc);
-  }
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  size_t size() const override;
-
- private:
-  std::string origin_;
-  SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_;
-};
-
-class QUICHE_EXPORT SpdyPriorityIR : public SpdyFrameIR {
- public:
-  SpdyPriorityIR(SpdyStreamId stream_id, SpdyStreamId parent_stream_id,
-                 int weight, bool exclusive)
-      : SpdyFrameIR(stream_id),
-        parent_stream_id_(parent_stream_id),
-        weight_(weight),
-        exclusive_(exclusive) {}
-  SpdyPriorityIR(const SpdyPriorityIR&) = delete;
-  SpdyPriorityIR& operator=(const SpdyPriorityIR&) = delete;
-  SpdyStreamId parent_stream_id() const { return parent_stream_id_; }
-  int weight() const { return weight_; }
-  bool exclusive() const { return exclusive_; }
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  size_t size() const override;
-
- private:
-  SpdyStreamId parent_stream_id_;
-  int weight_;
-  bool exclusive_;
-};
-
-class QUICHE_EXPORT SpdyPriorityUpdateIR : public SpdyFrameIR {
- public:
-  SpdyPriorityUpdateIR(SpdyStreamId stream_id,
-                       SpdyStreamId prioritized_stream_id,
-                       std::string priority_field_value)
-      : SpdyFrameIR(stream_id),
-        prioritized_stream_id_(prioritized_stream_id),
-        priority_field_value_(std::move(priority_field_value)) {}
-  SpdyPriorityUpdateIR(const SpdyPriorityUpdateIR&) = delete;
-  SpdyPriorityUpdateIR& operator=(const SpdyPriorityUpdateIR&) = delete;
-  SpdyStreamId prioritized_stream_id() const { return prioritized_stream_id_; }
-  const std::string& priority_field_value() const {
-    return priority_field_value_;
-  }
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  size_t size() const override;
-
- private:
-  SpdyStreamId prioritized_stream_id_;
-  std::string priority_field_value_;
-};
-
-struct QUICHE_EXPORT AcceptChOriginValuePair {
-  std::string origin;
-  std::string value;
-  bool operator==(const AcceptChOriginValuePair& rhs) const {
-    return origin == rhs.origin && value == rhs.value;
-  }
-};
-
-class QUICHE_EXPORT SpdyAcceptChIR : public SpdyFrameIR {
- public:
-  SpdyAcceptChIR(std::vector<AcceptChOriginValuePair> entries)
-      : entries_(std::move(entries)) {}
-  SpdyAcceptChIR(const SpdyAcceptChIR&) = delete;
-  SpdyAcceptChIR& operator=(const SpdyAcceptChIR&) = delete;
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  size_t size() const override;
-
-  const std::vector<AcceptChOriginValuePair>& entries() const {
-    return entries_;
-  }
-
- private:
-  std::vector<AcceptChOriginValuePair> entries_;
-};
-
-// Represents a frame of unrecognized type.
-class QUICHE_EXPORT SpdyUnknownIR : public SpdyFrameIR {
- public:
-  SpdyUnknownIR(SpdyStreamId stream_id, uint8_t type, uint8_t flags,
-                std::string payload)
-      : SpdyFrameIR(stream_id),
-        type_(type),
-        flags_(flags),
-        length_(payload.size()),
-        payload_(std::move(payload)) {}
-  SpdyUnknownIR(const SpdyUnknownIR&) = delete;
-  SpdyUnknownIR& operator=(const SpdyUnknownIR&) = delete;
-  uint8_t type() const { return type_; }
-  uint8_t flags() const { return flags_; }
-  size_t length() const { return length_; }
-  const std::string& payload() const { return payload_; }
-
-  void Visit(SpdyFrameVisitor* visitor) const override;
-
-  SpdyFrameType frame_type() const override;
-
-  int flow_control_window_consumed() const override;
-
-  size_t size() const override;
-
- protected:
-  // Allows subclasses to overwrite the default payload length.
-  void set_length(size_t length) { length_ = length; }
-
- private:
-  uint8_t type_;
-  uint8_t flags_;
-  size_t length_;
-  const std::string payload_;
-};
-
-class QUICHE_EXPORT SpdySerializedFrame {
- public:
-  SpdySerializedFrame() : size_(0) {}
-
-  // Creates a valid SpdySerializedFrame using a pre-created buffer.
-  SpdySerializedFrame(std::unique_ptr<char[]> data, size_t size)
-      : frame_(std::move(data)), size_(size) {}
-
-  SpdySerializedFrame(SpdySerializedFrame&& other)
-      : frame_(std::move(other.frame_)), size_(other.size_) {}
-
-  SpdySerializedFrame(const SpdySerializedFrame&) = delete;
-  SpdySerializedFrame& operator=(const SpdySerializedFrame&) = delete;
-
-  SpdySerializedFrame& operator=(SpdySerializedFrame&& other) {
-    // Take over |other|.
-    frame_ = std::move(other.frame_);
-    size_ = other.size_;
-    return *this;
-  }
-
-  ~SpdySerializedFrame() = default;
-
-  // Provides access to the frame bytes, which is a buffer containing the frame
-  // packed as expected for sending over the wire.
-  char* data() const { return frame_.get(); }
-
-  // Returns the actual size of the underlying buffer.
-  size_t size() const { return size_; }
-
-  operator absl::string_view() const {
-    return absl::string_view{frame_.get(), size_};
-  }
-
- private:
-  std::unique_ptr<char[]> frame_;
-  size_t size_;
-};
-
-// This interface is for classes that want to process SpdyFrameIRs without
-// having to know what type they are.  An instance of this interface can be
-// passed to a SpdyFrameIR's Visit method, and the appropriate type-specific
-// method of this class will be called.
-class QUICHE_EXPORT SpdyFrameVisitor {
- public:
-  SpdyFrameVisitor() {}
-  SpdyFrameVisitor(const SpdyFrameVisitor&) = delete;
-  SpdyFrameVisitor& operator=(const SpdyFrameVisitor&) = delete;
-  virtual ~SpdyFrameVisitor() {}
-
-  virtual void VisitRstStream(const SpdyRstStreamIR& rst_stream) = 0;
-  virtual void VisitSettings(const SpdySettingsIR& settings) = 0;
-  virtual void VisitPing(const SpdyPingIR& ping) = 0;
-  virtual void VisitGoAway(const SpdyGoAwayIR& goaway) = 0;
-  virtual void VisitHeaders(const SpdyHeadersIR& headers) = 0;
-  virtual void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) = 0;
-  virtual void VisitPushPromise(const SpdyPushPromiseIR& push_promise) = 0;
-  virtual void VisitContinuation(const SpdyContinuationIR& continuation) = 0;
-  virtual void VisitAltSvc(const SpdyAltSvcIR& altsvc) = 0;
-  virtual void VisitPriority(const SpdyPriorityIR& priority) = 0;
-  virtual void VisitData(const SpdyDataIR& data) = 0;
-  virtual void VisitPriorityUpdate(
-      const SpdyPriorityUpdateIR& priority_update) = 0;
-  virtual void VisitAcceptCh(const SpdyAcceptChIR& accept_ch) = 0;
-  virtual void VisitUnknown(const SpdyUnknownIR& /*unknown*/) {
-    // TODO(birenroy): make abstract.
-  }
-};
-
-// Optionally, and in addition to SpdyFramerVisitorInterface, a class supporting
-// SpdyFramerDebugVisitorInterface may be used in conjunction with SpdyFramer in
-// order to extract debug/internal information about the SpdyFramer as it
-// operates.
-//
-// Most HTTP2 implementations need not bother with this interface at all.
-class QUICHE_EXPORT SpdyFramerDebugVisitorInterface {
- public:
-  virtual ~SpdyFramerDebugVisitorInterface() {}
-
-  // Called after compressing a frame with a payload of
-  // a list of name-value pairs.
-  // |payload_len| is the uncompressed payload size.
-  // |frame_len| is the compressed frame size.
-  virtual void OnSendCompressedFrame(SpdyStreamId /*stream_id*/,
-                                     SpdyFrameType /*type*/,
-                                     size_t /*payload_len*/,
-                                     size_t /*frame_len*/) {}
-
-  // Called when a frame containing a compressed payload of
-  // name-value pairs is received.
-  // |frame_len| is the compressed frame size.
-  virtual void OnReceiveCompressedFrame(SpdyStreamId /*stream_id*/,
-                                        SpdyFrameType /*type*/,
-                                        size_t /*frame_len*/) {}
-};
-
-// Calculates the number of bytes required to serialize a SpdyHeadersIR, not
-// including the bytes to be used for the encoded header set.
-size_t GetHeaderFrameSizeSansBlock(const SpdyHeadersIR& header_ir);
-
-// Calculates the number of bytes required to serialize a SpdyPushPromiseIR,
-// not including the bytes to be used for the encoded header set.
-size_t GetPushPromiseFrameSizeSansBlock(
-    const SpdyPushPromiseIR& push_promise_ir);
-
-}  // namespace spdy
+#include "quiche/http2/core/spdy_protocol.h"
 
 #endif  // QUICHE_SPDY_CORE_SPDY_PROTOCOL_H_