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_