mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
1014 lines
35 KiB
C++
1014 lines
35 KiB
C++
// 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 NET_SPDY_CORE_SPDY_PROTOCOL_H_
|
|
#define NET_SPDY_CORE_SPDY_PROTOCOL_H_
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include <iosfwd>
|
|
#include <limits>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <new>
|
|
#include <utility>
|
|
|
|
#include "base/compiler_specific.h"
|
|
#include "base/logging.h"
|
|
#include "base/macros.h"
|
|
#include "base/sys_byteorder.h"
|
|
#include "net/spdy/core/spdy_alt_svc_wire_format.h"
|
|
#include "net/spdy/core/spdy_bitmasks.h"
|
|
#include "net/spdy/core/spdy_bug_tracker.h"
|
|
#include "net/spdy/core/spdy_header_block.h"
|
|
#include "net/spdy/platform/api/spdy_export.h"
|
|
#include "net/spdy/platform/api/spdy_ptr_util.h"
|
|
#include "net/spdy/platform/api/spdy_string.h"
|
|
#include "net/spdy/platform/api/spdy_string_piece.h"
|
|
|
|
namespace net {
|
|
|
|
// A stream id is a 31 bit entity.
|
|
typedef uint32_t SpdyStreamId;
|
|
|
|
// Specifies the stream ID used to denote the current session (for
|
|
// flow control).
|
|
const SpdyStreamId kSessionFlowControlStreamId = 0;
|
|
|
|
// Max stream id.
|
|
const SpdyStreamId kMaxStreamId = 0x7fffffff;
|
|
|
|
// The maximum possible frame payload size allowed by the spec.
|
|
const 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.
|
|
const uint32_t kHttp2DefaultFramePayloadLimit = 1 << 14;
|
|
|
|
// Number of octets in the frame header.
|
|
const 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.
|
|
const 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.
|
|
const uint32_t kSpdyInitialHeaderListSizeLimit = 0xFFFFFFFF;
|
|
|
|
// Maximum window size for a Spdy stream or session.
|
|
const int32_t kSpdyMaximumWindowSize = 0x7FFFFFFF; // Max signed 32bit int
|
|
|
|
// Maximum padding size in octets for one DATA or HEADERS or PUSH_PROMISE frame.
|
|
const 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.
|
|
SPDY_EXPORT_PRIVATE extern const char* const kHttp2ConnectionHeaderPrefix;
|
|
const 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,
|
|
MAX_FRAME_TYPE = ALTSVC,
|
|
// The specific value of EXTENSION is meaningless; it is a placeholder used
|
|
// within SpdyFramer's state machine when handling unknown frames via an
|
|
// extension API.
|
|
// TODO(birenroy): Remove the fake EXTENSION value from the SpdyFrameType
|
|
// enum.
|
|
EXTENSION = 0xff
|
|
};
|
|
|
|
// 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,
|
|
CONTROL_FLAG_UNIDIRECTIONAL = 0x02,
|
|
};
|
|
|
|
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 SpdySettingsIds : uint16_t {
|
|
// 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,
|
|
SETTINGS_MAX = SETTINGS_MAX_HEADER_LIST_SIZE
|
|
};
|
|
|
|
// This explicit operator is needed, otherwise compiler finds
|
|
// overloaded operator to be ambiguous.
|
|
SPDY_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out,
|
|
SpdySettingsIds id);
|
|
|
|
// This operator is needed, because SpdyFrameType is an enum class,
|
|
// therefore implicit conversion to underlying integer type is not allowed.
|
|
SPDY_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out,
|
|
SpdyFrameType frame_type);
|
|
|
|
using SettingsMap = std::map<SpdySettingsIds, 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
|
|
};
|
|
|
|
// 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
|
|
const SpdyPriority kV3HighestPriority = 0;
|
|
const SpdyPriority kV3LowestPriority = 7;
|
|
|
|
// Returns SPDY 3.x priority value clamped to the valid range of [0, 7].
|
|
SPDY_EXPORT_PRIVATE 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.
|
|
const int kHttp2MinStreamWeight = 1;
|
|
const int kHttp2MaxStreamWeight = 256;
|
|
const int kHttp2DefaultStreamWeight = 16;
|
|
|
|
// Returns HTTP/2 weight clamped to the valid range of [1, 256].
|
|
SPDY_EXPORT_PRIVATE 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.
|
|
SPDY_EXPORT_PRIVATE 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).
|
|
SPDY_EXPORT_PRIVATE 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.
|
|
SPDY_EXPORT_PRIVATE 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.
|
|
SPDY_EXPORT_PRIVATE SpdyFrameType ParseFrameType(uint8_t frame_type_field);
|
|
|
|
// Serializes a frame type to the on-the-wire value.
|
|
SPDY_EXPORT_PRIVATE 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.
|
|
SPDY_EXPORT_PRIVATE bool IsValidHTTP2FrameStreamId(
|
|
SpdyStreamId current_frame_stream_id,
|
|
SpdyFrameType frame_type_field);
|
|
|
|
// Serialize |frame_type| to string for logging/debugging.
|
|
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.
|
|
SPDY_EXPORT_PRIVATE bool ParseSettingsId(uint16_t wire_setting_id,
|
|
SpdySettingsIds* setting_id);
|
|
|
|
// Return if |id| corresponds to a defined setting;
|
|
// stringify |id| to |*settings_id_string| regardless.
|
|
SPDY_EXPORT_PRIVATE bool SettingsIdToString(SpdySettingsIds id,
|
|
const char** settings_id_string);
|
|
|
|
// Parse |wire_error_code| to a SpdyErrorCode.
|
|
// Treat unrecognized error codes as INTERNAL_ERROR
|
|
// as recommended by the HTTP/2 specification.
|
|
SPDY_EXPORT_PRIVATE SpdyErrorCode ParseErrorCode(uint32_t wire_error_code);
|
|
|
|
// Serialize RST_STREAM or GOAWAY frame error code to string
|
|
// for logging/debugging.
|
|
const char* ErrorCodeToString(SpdyErrorCode error_code);
|
|
|
|
// Minimum size of a frame, in octets.
|
|
const size_t kFrameMinimumSize = kFrameHeaderSize;
|
|
|
|
// Minimum frame size for variable size frame types (includes mandatory fields),
|
|
// frame size for fixed size frames, in octets.
|
|
|
|
const size_t kDataFrameMinimumSize = kFrameHeaderSize;
|
|
const size_t kHeadersFrameMinimumSize = kFrameHeaderSize;
|
|
// PRIORITY frame has stream_dependency (4 octets) and weight (1 octet) fields.
|
|
const size_t kPriorityFrameSize = kFrameHeaderSize + 5;
|
|
// RST_STREAM frame has error_code (4 octets) field.
|
|
const size_t kRstStreamFrameSize = kFrameHeaderSize + 4;
|
|
const size_t kSettingsFrameMinimumSize = kFrameHeaderSize;
|
|
// PUSH_PROMISE frame has promised_stream_id (4 octet) field.
|
|
const size_t kPushPromiseFrameMinimumSize = kFrameHeaderSize + 4;
|
|
// PING frame has opaque_bytes (8 octet) field.
|
|
const size_t kPingFrameSize = kFrameHeaderSize + 8;
|
|
// GOAWAY frame has last_stream_id (4 octet) and error_code (4 octet) fields.
|
|
const size_t kGoawayFrameMinimumSize = kFrameHeaderSize + 8;
|
|
// WINDOW_UPDATE frame has window_size_increment (4 octet) field.
|
|
const size_t kWindowUpdateFrameSize = kFrameHeaderSize + 4;
|
|
const size_t kContinuationFrameMinimumSize = kFrameHeaderSize;
|
|
// ALTSVC frame has origin_len (2 octets) field.
|
|
const size_t kGetAltSvcFrameMinimumSize = kFrameHeaderSize + 2;
|
|
|
|
// Maximum possible configurable size of a frame in octets.
|
|
const size_t kMaxFrameSizeLimit = kSpdyMaxFrameSizeLimit + kFrameHeaderSize;
|
|
// Size of a header block size field.
|
|
const size_t kSizeOfSizeField = sizeof(uint32_t);
|
|
// Per-header overhead for block size accounting in bytes.
|
|
const size_t kPerHeaderOverhead = 32;
|
|
// Initial window size for a stream in bytes.
|
|
const int32_t kInitialStreamWindowSize = 64 * 1024 - 1;
|
|
// Initial window size for a session in bytes.
|
|
const int32_t kInitialSessionWindowSize = 64 * 1024 - 1;
|
|
// The NPN string for HTTP2, "h2".
|
|
extern const char* const kHttp2Npn;
|
|
|
|
// Names of pseudo-headers defined for HTTP/2 requests.
|
|
SPDY_EXPORT_PRIVATE extern const char* const kHttp2AuthorityHeader;
|
|
SPDY_EXPORT_PRIVATE extern const char* const kHttp2MethodHeader;
|
|
SPDY_EXPORT_PRIVATE extern const char* const kHttp2PathHeader;
|
|
SPDY_EXPORT_PRIVATE extern const char* const kHttp2SchemeHeader;
|
|
|
|
// Name of pseudo-header defined for HTTP/2 responses.
|
|
SPDY_EXPORT_PRIVATE extern const char* const kHttp2StatusHeader;
|
|
|
|
// Variant type (i.e. tagged union) 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 StreamPrecedence {
|
|
public:
|
|
// Constructs instance that is a SPDY 3.x priority. Clamps priority value to
|
|
// the valid range [0, 7].
|
|
explicit StreamPrecedence(SpdyPriority priority)
|
|
: is_spdy3_priority_(true),
|
|
spdy3_priority_(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)
|
|
: is_spdy3_priority_(false),
|
|
http2_stream_dependency_{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 is_spdy3_priority_; }
|
|
|
|
// 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_
|
|
? spdy3_priority_
|
|
: Http2WeightToSpdy3Priority(http2_stream_dependency_.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
|
|
: http2_stream_dependency_.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(spdy3_priority_)
|
|
: http2_stream_dependency_.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 !is_spdy3_priority_ && http2_stream_dependency_.is_exclusive;
|
|
}
|
|
|
|
// Facilitates test assertions.
|
|
bool operator==(const StreamPrecedence& other) const {
|
|
if (is_spdy3_priority()) {
|
|
return other.is_spdy3_priority() &&
|
|
(spdy3_priority() == other.spdy3_priority());
|
|
} else {
|
|
return !other.is_spdy3_priority() && (parent_id() == other.parent_id()) &&
|
|
(weight() == other.weight()) &&
|
|
(is_exclusive() == other.is_exclusive());
|
|
}
|
|
}
|
|
|
|
bool operator!=(const StreamPrecedence& other) const {
|
|
return !(*this == other);
|
|
}
|
|
|
|
private:
|
|
struct Http2StreamDependency {
|
|
StreamIdType parent_id;
|
|
int weight;
|
|
bool is_exclusive;
|
|
};
|
|
|
|
bool is_spdy3_priority_;
|
|
union {
|
|
SpdyPriority spdy3_priority_;
|
|
Http2StreamDependency http2_stream_dependency_;
|
|
};
|
|
};
|
|
|
|
typedef StreamPrecedence<SpdyStreamId> SpdyStreamPrecedence;
|
|
|
|
class SpdyFrameVisitor;
|
|
|
|
// Intermediate representation for HTTP2 frames.
|
|
class SPDY_EXPORT_PRIVATE 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 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) {}
|
|
|
|
private:
|
|
SpdyStreamId stream_id_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyFrameIR);
|
|
};
|
|
|
|
// Abstract class intended to be inherited by IRs that have the option of a FIN
|
|
// flag.
|
|
class SPDY_EXPORT_PRIVATE 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) {}
|
|
|
|
private:
|
|
bool fin_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithFinIR);
|
|
};
|
|
|
|
// Abstract class intended to be inherited by IRs that contain a header
|
|
// block. Implies SpdyFrameWithFinIR.
|
|
class SPDY_EXPORT_PRIVATE SpdyFrameWithHeaderBlockIR
|
|
: public SpdyFrameWithFinIR {
|
|
public:
|
|
~SpdyFrameWithHeaderBlockIR() override;
|
|
|
|
const SpdyHeaderBlock& header_block() const { return header_block_; }
|
|
void set_header_block(SpdyHeaderBlock header_block) {
|
|
// Deep copy.
|
|
header_block_ = std::move(header_block);
|
|
}
|
|
void SetHeader(SpdyStringPiece name, SpdyStringPiece value) {
|
|
header_block_[name] = value;
|
|
}
|
|
|
|
protected:
|
|
SpdyFrameWithHeaderBlockIR(SpdyStreamId stream_id,
|
|
SpdyHeaderBlock header_block);
|
|
|
|
private:
|
|
SpdyHeaderBlock header_block_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithHeaderBlockIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE SpdyDataIR : public SpdyFrameWithFinIR {
|
|
public:
|
|
// Performs a deep copy on data.
|
|
SpdyDataIR(SpdyStreamId stream_id, SpdyStringPiece 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, SpdyString data);
|
|
|
|
// Use in conjunction with SetDataShallow() for shallow-copy on data.
|
|
explicit SpdyDataIR(SpdyStreamId stream_id);
|
|
|
|
~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) {
|
|
DCHECK_GT(padding_len, 0);
|
|
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(SpdyStringPiece data) {
|
|
data_store_ = SpdyMakeUnique<SpdyString>(data.data(), data.size());
|
|
data_ = data_store_->data();
|
|
data_len_ = data.size();
|
|
}
|
|
|
|
// Shallow-copy of data (do not keep private copy).
|
|
void SetDataShallow(SpdyStringPiece 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;
|
|
|
|
private:
|
|
// Used to store data that this SpdyDataIR should own.
|
|
std::unique_ptr<SpdyString> 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_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyDataIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE SpdyRstStreamIR : public SpdyFrameIR {
|
|
public:
|
|
SpdyRstStreamIR(SpdyStreamId stream_id, SpdyErrorCode error_code);
|
|
|
|
~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;
|
|
|
|
private:
|
|
SpdyErrorCode error_code_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyRstStreamIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE SpdySettingsIR : public SpdyFrameIR {
|
|
public:
|
|
SpdySettingsIR();
|
|
~SpdySettingsIR() override;
|
|
|
|
// Overwrites as appropriate.
|
|
const SettingsMap& values() const { return values_; }
|
|
void AddSetting(SpdySettingsIds 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;
|
|
|
|
private:
|
|
SettingsMap values_;
|
|
bool is_ack_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdySettingsIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE SpdyPingIR : public SpdyFrameIR {
|
|
public:
|
|
explicit SpdyPingIR(SpdyPingId id) : id_(id), is_ack_(false) {}
|
|
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;
|
|
|
|
private:
|
|
SpdyPingId id_;
|
|
bool is_ack_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyPingIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE 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,
|
|
SpdyStringPiece 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,
|
|
SpdyString description);
|
|
|
|
~SpdyGoAwayIR() override;
|
|
|
|
SpdyStreamId last_good_stream_id() const { return last_good_stream_id_; }
|
|
void set_last_good_stream_id(SpdyStreamId last_good_stream_id) {
|
|
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 SpdyStringPiece& description() const { return description_; }
|
|
|
|
void Visit(SpdyFrameVisitor* visitor) const override;
|
|
|
|
SpdyFrameType frame_type() const override;
|
|
|
|
private:
|
|
SpdyStreamId last_good_stream_id_;
|
|
SpdyErrorCode error_code_;
|
|
const SpdyString description_store_;
|
|
const SpdyStringPiece description_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyGoAwayIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE SpdyHeadersIR : public SpdyFrameWithHeaderBlockIR {
|
|
public:
|
|
explicit SpdyHeadersIR(SpdyStreamId stream_id)
|
|
: SpdyHeadersIR(stream_id, SpdyHeaderBlock()) {}
|
|
SpdyHeadersIR(SpdyStreamId stream_id, SpdyHeaderBlock header_block)
|
|
: SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)) {}
|
|
|
|
void Visit(SpdyFrameVisitor* visitor) const override;
|
|
|
|
SpdyFrameType frame_type() 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) {
|
|
DCHECK_GT(padding_len, 0);
|
|
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;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyHeadersIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE SpdyWindowUpdateIR : public SpdyFrameIR {
|
|
public:
|
|
SpdyWindowUpdateIR(SpdyStreamId stream_id, int32_t delta)
|
|
: SpdyFrameIR(stream_id) {
|
|
set_delta(delta);
|
|
}
|
|
int32_t delta() const { return delta_; }
|
|
void set_delta(int32_t delta) {
|
|
DCHECK_LE(0, delta);
|
|
DCHECK_LE(delta, kSpdyMaximumWindowSize);
|
|
delta_ = delta;
|
|
}
|
|
|
|
void Visit(SpdyFrameVisitor* visitor) const override;
|
|
|
|
SpdyFrameType frame_type() const override;
|
|
|
|
private:
|
|
int32_t delta_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyWindowUpdateIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE SpdyPushPromiseIR
|
|
: public SpdyFrameWithHeaderBlockIR {
|
|
public:
|
|
SpdyPushPromiseIR(SpdyStreamId stream_id, SpdyStreamId promised_stream_id)
|
|
: SpdyPushPromiseIR(stream_id, promised_stream_id, SpdyHeaderBlock()) {}
|
|
SpdyPushPromiseIR(SpdyStreamId stream_id,
|
|
SpdyStreamId promised_stream_id,
|
|
SpdyHeaderBlock header_block)
|
|
: SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)),
|
|
promised_stream_id_(promised_stream_id),
|
|
padded_(false),
|
|
padding_payload_len_(0) {}
|
|
SpdyStreamId promised_stream_id() const { return promised_stream_id_; }
|
|
|
|
void Visit(SpdyFrameVisitor* visitor) const override;
|
|
|
|
SpdyFrameType frame_type() const override;
|
|
|
|
bool padded() const { return padded_; }
|
|
int padding_payload_len() const { return padding_payload_len_; }
|
|
void set_padding_len(int padding_len) {
|
|
DCHECK_GT(padding_len, 0);
|
|
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_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyPushPromiseIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE SpdyContinuationIR : public SpdyFrameIR {
|
|
public:
|
|
explicit SpdyContinuationIR(SpdyStreamId stream_id);
|
|
~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 SpdyString& encoding() const { return *encoding_; }
|
|
void take_encoding(std::unique_ptr<SpdyString> encoding) {
|
|
encoding_ = std::move(encoding);
|
|
}
|
|
|
|
private:
|
|
std::unique_ptr<SpdyString> encoding_;
|
|
bool end_headers_;
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyContinuationIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE SpdyAltSvcIR : public SpdyFrameIR {
|
|
public:
|
|
explicit SpdyAltSvcIR(SpdyStreamId stream_id);
|
|
~SpdyAltSvcIR() override;
|
|
|
|
SpdyString origin() const { return origin_; }
|
|
const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector() const {
|
|
return altsvc_vector_;
|
|
}
|
|
|
|
void set_origin(SpdyString 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;
|
|
|
|
private:
|
|
SpdyString origin_;
|
|
SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_;
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyAltSvcIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE 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) {}
|
|
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;
|
|
|
|
private:
|
|
SpdyStreamId parent_stream_id_;
|
|
int weight_;
|
|
bool exclusive_;
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyPriorityIR);
|
|
};
|
|
|
|
// Represents a frame of unrecognized type.
|
|
class SPDY_EXPORT_PRIVATE SpdyUnknownIR : public SpdyFrameIR {
|
|
public:
|
|
SpdyUnknownIR(SpdyStreamId stream_id,
|
|
uint8_t type,
|
|
uint8_t flags,
|
|
SpdyString payload)
|
|
: SpdyFrameIR(stream_id),
|
|
type_(type),
|
|
flags_(flags),
|
|
length_(payload.size()),
|
|
payload_(std::move(payload)) {}
|
|
uint8_t type() const { return type_; }
|
|
uint8_t flags() const { return flags_; }
|
|
int length() const { return length_; }
|
|
const SpdyString& payload() const { return payload_; }
|
|
|
|
void Visit(SpdyFrameVisitor* visitor) const override;
|
|
|
|
SpdyFrameType frame_type() const override;
|
|
|
|
int flow_control_window_consumed() const override;
|
|
|
|
protected:
|
|
// Allows subclasses to overwrite the default length.
|
|
void set_length(int length) { length_ = length; }
|
|
|
|
private:
|
|
uint8_t type_;
|
|
uint8_t flags_;
|
|
int length_;
|
|
const SpdyString payload_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyUnknownIR);
|
|
};
|
|
|
|
class SPDY_EXPORT_PRIVATE SpdySerializedFrame {
|
|
public:
|
|
SpdySerializedFrame()
|
|
: frame_(const_cast<char*>("")), size_(0), owns_buffer_(false) {}
|
|
|
|
// Create a valid SpdySerializedFrame using a pre-created buffer.
|
|
// If |owns_buffer| is true, this class takes ownership of the buffer and will
|
|
// delete it on cleanup. The buffer must have been created using new char[].
|
|
// If |owns_buffer| is false, the caller retains ownership of the buffer and
|
|
// is responsible for making sure the buffer outlives this frame. In other
|
|
// words, this class does NOT create a copy of the buffer.
|
|
SpdySerializedFrame(char* data, size_t size, bool owns_buffer)
|
|
: frame_(data), size_(size), owns_buffer_(owns_buffer) {}
|
|
|
|
SpdySerializedFrame(SpdySerializedFrame&& other)
|
|
: frame_(other.frame_),
|
|
size_(other.size_),
|
|
owns_buffer_(other.owns_buffer_) {
|
|
// |other| is no longer responsible for the buffer.
|
|
other.owns_buffer_ = false;
|
|
}
|
|
|
|
SpdySerializedFrame& operator=(SpdySerializedFrame&& other) {
|
|
// Free buffer if necessary.
|
|
if (owns_buffer_) {
|
|
delete[] frame_;
|
|
}
|
|
// Take over |other|.
|
|
frame_ = other.frame_;
|
|
size_ = other.size_;
|
|
owns_buffer_ = other.owns_buffer_;
|
|
// |other| is no longer responsible for the buffer.
|
|
other.owns_buffer_ = false;
|
|
return *this;
|
|
}
|
|
|
|
~SpdySerializedFrame() {
|
|
if (owns_buffer_) {
|
|
delete[] frame_;
|
|
}
|
|
}
|
|
|
|
// 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_; }
|
|
|
|
// Returns the actual size of the underlying buffer.
|
|
size_t size() const { return size_; }
|
|
|
|
// Returns a buffer containing the contents of the frame, of which the caller
|
|
// takes ownership, and clears this SpdySerializedFrame.
|
|
char* ReleaseBuffer() {
|
|
char* buffer;
|
|
if (owns_buffer_) {
|
|
// If the buffer is owned, relinquish ownership to the caller.
|
|
buffer = frame_;
|
|
owns_buffer_ = false;
|
|
} else {
|
|
// Otherwise, we need to make a copy to give to the caller.
|
|
buffer = new char[size_];
|
|
memcpy(buffer, frame_, size_);
|
|
}
|
|
*this = SpdySerializedFrame();
|
|
return buffer;
|
|
}
|
|
|
|
// Returns the estimate of dynamically allocated memory in bytes.
|
|
size_t EstimateMemoryUsage() const { return owns_buffer_ ? size_ : 0; }
|
|
|
|
protected:
|
|
char* frame_;
|
|
|
|
private:
|
|
size_t size_;
|
|
bool owns_buffer_;
|
|
DISALLOW_COPY_AND_ASSIGN(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 SPDY_EXPORT_PRIVATE SpdyFrameVisitor {
|
|
public:
|
|
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 VisitUnknown(const SpdyUnknownIR& unknown) {
|
|
// TODO(birenroy): make abstract.
|
|
}
|
|
|
|
protected:
|
|
SpdyFrameVisitor() {}
|
|
virtual ~SpdyFrameVisitor() {}
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(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 SPDY_EXPORT_PRIVATE 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 net
|
|
|
|
#endif // NET_SPDY_CORE_SPDY_PROTOCOL_H_
|