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_