chromium/net/third_party/quiche/src/quiche/http2/core/spdy_protocol.h

// 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_