// 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. SpdyStreamId; // A SETTINGS ID is a 16-bit entity. SpdySettingsId; // Specifies the stream ID used to denote the current session (for // flow control). inline constexpr SpdyStreamId kSessionFlowControlStreamId = …; // 0 is not a valid stream ID for any other purpose than flow control. inline constexpr SpdyStreamId kInvalidStreamId = …; // Max stream id. inline constexpr SpdyStreamId kMaxStreamId = …; // The maximum possible frame payload size allowed by the spec. inline constexpr uint32_t kSpdyMaxFrameSizeLimit = …; // 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 = …; // 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 = …; // Number of octets in the frame header. inline constexpr size_t kFrameHeaderSize = …; // 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 = …; // 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 = …; // Maximum window size for a Spdy stream or session. inline constexpr int32_t kSpdyMaximumWindowSize = …; // Max signed 32bit int // Maximum padding size in octets for one DATA or HEADERS or PUSH_PROMISE frame. inline constexpr int32_t kPaddingSizePerFrame = …; // 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 = …; // Wire values for HTTP2 frame types. enum class SpdyFrameType : uint8_t { … }; // Flags on data packets. enum SpdyDataFlags { … }; // Flags on control packets enum SpdyControlFlags { … }; enum SpdyPingFlags { … }; // Used by HEADERS, PUSH_PROMISE, and CONTINUATION. enum SpdyHeadersFlags { … }; enum SpdyPushPromiseFlags { … }; enum Http2SettingsControlFlags { … }; // Wire values of HTTP/2 setting identifiers. enum SpdyKnownSettingsId : SpdySettingsId { … }; // 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); SettingsMap; // HTTP/2 error codes, RFC 7540 Section 7. enum SpdyErrorCode : uint32_t { … }; // Type of priority write scheduler. enum class WriteSchedulerType { … }; // A SPDY priority is a number between 0 and 7 (inclusive). 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 = …; inline constexpr SpdyPriority kV3LowestPriority = …; // 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 = …; inline constexpr int kHttp2MaxStreamWeight = …; inline constexpr int kHttp2DefaultStreamWeight = …; // 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 = …; 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 = …; // Minimum frame size for variable size frame types (includes mandatory fields), // frame size for fixed size frames, in octets. inline constexpr size_t kDataFrameMinimumSize = …; inline constexpr size_t kHeadersFrameMinimumSize = …; // PRIORITY frame has stream_dependency (4 octets) and weight (1 octet) fields. inline constexpr size_t kPriorityFrameSize = …; // RST_STREAM frame has error_code (4 octets) field. inline constexpr size_t kRstStreamFrameSize = …; inline constexpr size_t kSettingsFrameMinimumSize = …; inline constexpr size_t kSettingsOneSettingSize = …; // PUSH_PROMISE frame has promised_stream_id (4 octet) field. inline constexpr size_t kPushPromiseFrameMinimumSize = …; // PING frame has opaque_bytes (8 octet) field. inline constexpr size_t kPingFrameSize = …; // GOAWAY frame has last_stream_id (4 octet) and error_code (4 octet) fields. inline constexpr size_t kGoawayFrameMinimumSize = …; // WINDOW_UPDATE frame has window_size_increment (4 octet) field. inline constexpr size_t kWindowUpdateFrameSize = …; inline constexpr size_t kContinuationFrameMinimumSize = …; // ALTSVC frame has origin_len (2 octets) field. inline constexpr size_t kGetAltSvcFrameMinimumSize = …; // PRIORITY_UPDATE frame has prioritized_stream_id (4 octets) field. inline constexpr size_t kPriorityUpdateFrameMinimumSize = …; // ACCEPT_CH frame may have empty payload. inline constexpr size_t kAcceptChFrameMinimumSize = …; // Each ACCEPT_CH frame entry has a 16-bit origin length and a 16-bit value // length. inline constexpr size_t kAcceptChFramePerEntryOverhead = …; // Maximum possible configurable size of a frame in octets. inline constexpr size_t kMaxFrameSizeLimit = …; // Size of a header block size field. inline constexpr size_t kSizeOfSizeField = …; // Initial window size for a stream in bytes. inline constexpr int32_t kInitialStreamWindowSize = …; // Initial window size for a session in bytes. inline constexpr int32_t kInitialSessionWindowSize = …; // 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. inline constexpr size_t kPerHeaderHpackOverhead = …; // 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 { … }; SpdyStreamPrecedence; class SpdyFrameVisitor; // Intermediate representation for HTTP2 frames. class QUICHE_EXPORT SpdyFrameIR { … }; // Abstract class intended to be inherited by IRs that have the option of a FIN // flag. class QUICHE_EXPORT SpdyFrameWithFinIR : public SpdyFrameIR { … }; // Abstract class intended to be inherited by IRs that contain a header // block. Implies SpdyFrameWithFinIR. class QUICHE_EXPORT SpdyFrameWithHeaderBlockIR : public SpdyFrameWithFinIR { … }; class QUICHE_EXPORT SpdyDataIR : public SpdyFrameWithFinIR { … }; class QUICHE_EXPORT SpdyRstStreamIR : public SpdyFrameIR { … }; class QUICHE_EXPORT SpdySettingsIR : public SpdyFrameIR { … }; class QUICHE_EXPORT SpdyPingIR : public SpdyFrameIR { … }; class QUICHE_EXPORT SpdyGoAwayIR : public SpdyFrameIR { … }; class QUICHE_EXPORT SpdyHeadersIR : public SpdyFrameWithHeaderBlockIR { … }; class QUICHE_EXPORT SpdyWindowUpdateIR : public SpdyFrameIR { … }; class QUICHE_EXPORT SpdyPushPromiseIR : public SpdyFrameWithHeaderBlockIR { … }; class QUICHE_EXPORT SpdyContinuationIR : public SpdyFrameIR { … }; class QUICHE_EXPORT SpdyAltSvcIR : public SpdyFrameIR { … }; class QUICHE_EXPORT SpdyPriorityIR : public SpdyFrameIR { … }; class QUICHE_EXPORT SpdyPriorityUpdateIR : public SpdyFrameIR { … }; struct QUICHE_EXPORT AcceptChOriginValuePair { … }; class QUICHE_EXPORT SpdyAcceptChIR : public SpdyFrameIR { … }; // Represents a frame of unrecognized type. class QUICHE_EXPORT SpdyUnknownIR : public SpdyFrameIR { … }; class QUICHE_EXPORT SpdySerializedFrame { … }; // 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 { … }; // 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 { … }; // 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_