• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This file contains some protocol structures for use with SPDY 3 and HTTP 2
6 // The SPDY 3 spec can be found at:
7 // http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3
8 
9 #ifndef QUICHE_SPDY_CORE_SPDY_PROTOCOL_H_
10 #define QUICHE_SPDY_CORE_SPDY_PROTOCOL_H_
11 
12 #include <cstddef>
13 #include <cstdint>
14 #include <cstring>
15 #include <iosfwd>
16 #include <map>
17 #include <memory>
18 #include <string>
19 #include <utility>
20 #include <vector>
21 
22 #include "absl/strings/string_view.h"
23 #include "absl/types/variant.h"
24 #include "quiche/common/platform/api/quiche_export.h"
25 #include "quiche/common/platform/api/quiche_logging.h"
26 #include "quiche/spdy/core/http2_header_block.h"
27 #include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
28 #include "quiche/spdy/core/spdy_bitmasks.h"
29 
30 namespace spdy {
31 
32 // A stream ID is a 31-bit entity.
33 using SpdyStreamId = uint32_t;
34 
35 // A SETTINGS ID is a 16-bit entity.
36 using SpdySettingsId = uint16_t;
37 
38 // Specifies the stream ID used to denote the current session (for
39 // flow control).
40 inline constexpr SpdyStreamId kSessionFlowControlStreamId = 0;
41 
42 // 0 is not a valid stream ID for any other purpose than flow control.
43 inline constexpr SpdyStreamId kInvalidStreamId = 0;
44 
45 // Max stream id.
46 inline constexpr SpdyStreamId kMaxStreamId = 0x7fffffff;
47 
48 // The maximum possible frame payload size allowed by the spec.
49 inline constexpr uint32_t kSpdyMaxFrameSizeLimit = (1 << 24) - 1;
50 
51 // The initial value for the maximum frame payload size as per the spec. This is
52 // the maximum control frame size we accept.
53 inline constexpr uint32_t kHttp2DefaultFramePayloadLimit = 1 << 14;
54 
55 // The maximum size of the control frames that we send, including the size of
56 // the header. This limit is arbitrary. We can enforce it here or at the
57 // application layer. We chose the framing layer, but this can be changed (or
58 // removed) if necessary later down the line.
59 inline constexpr size_t kHttp2MaxControlFrameSendSize =
60     kHttp2DefaultFramePayloadLimit - 1;
61 
62 // Number of octets in the frame header.
63 inline constexpr size_t kFrameHeaderSize = 9;
64 
65 // The initial value for the maximum frame payload size as per the spec. This is
66 // the maximum control frame size we accept.
67 inline constexpr uint32_t kHttp2DefaultFrameSizeLimit =
68     kHttp2DefaultFramePayloadLimit + kFrameHeaderSize;
69 
70 // The initial value for the maximum size of the header list, "unlimited" (max
71 // unsigned 32-bit int) as per the spec.
72 inline constexpr uint32_t kSpdyInitialHeaderListSizeLimit = 0xFFFFFFFF;
73 
74 // Maximum window size for a Spdy stream or session.
75 inline constexpr int32_t kSpdyMaximumWindowSize =
76     0x7FFFFFFF;  // Max signed 32bit int
77 
78 // Maximum padding size in octets for one DATA or HEADERS or PUSH_PROMISE frame.
79 inline constexpr int32_t kPaddingSizePerFrame = 256;
80 
81 // The HTTP/2 connection preface, which must be the first bytes sent by the
82 // client upon starting an HTTP/2 connection, and which must be followed by a
83 // SETTINGS frame.  Note that even though |kHttp2ConnectionHeaderPrefix| is
84 // defined as a string literal with a null terminator, the actual connection
85 // preface is only the first |kHttp2ConnectionHeaderPrefixSize| bytes, which
86 // excludes the null terminator.
87 QUICHE_EXPORT extern const char* const kHttp2ConnectionHeaderPrefix;
88 inline constexpr int kHttp2ConnectionHeaderPrefixSize = 24;
89 
90 // Wire values for HTTP2 frame types.
91 enum class SpdyFrameType : uint8_t {
92   DATA = 0x00,
93   HEADERS = 0x01,
94   PRIORITY = 0x02,
95   RST_STREAM = 0x03,
96   SETTINGS = 0x04,
97   PUSH_PROMISE = 0x05,
98   PING = 0x06,
99   GOAWAY = 0x07,
100   WINDOW_UPDATE = 0x08,
101   CONTINUATION = 0x09,
102   // ALTSVC is a public extension.
103   ALTSVC = 0x0a,
104   PRIORITY_UPDATE = 0x10,
105   ACCEPT_CH = 0x89,
106 };
107 
108 // Flags on data packets.
109 enum SpdyDataFlags {
110   DATA_FLAG_NONE = 0x00,
111   DATA_FLAG_FIN = 0x01,
112   DATA_FLAG_PADDED = 0x08,
113 };
114 
115 // Flags on control packets
116 enum SpdyControlFlags {
117   CONTROL_FLAG_NONE = 0x00,
118   CONTROL_FLAG_FIN = 0x01,
119 };
120 
121 enum SpdyPingFlags {
122   PING_FLAG_ACK = 0x01,
123 };
124 
125 // Used by HEADERS, PUSH_PROMISE, and CONTINUATION.
126 enum SpdyHeadersFlags {
127   HEADERS_FLAG_END_HEADERS = 0x04,
128   HEADERS_FLAG_PADDED = 0x08,
129   HEADERS_FLAG_PRIORITY = 0x20,
130 };
131 
132 enum SpdyPushPromiseFlags {
133   PUSH_PROMISE_FLAG_END_PUSH_PROMISE = 0x04,
134   PUSH_PROMISE_FLAG_PADDED = 0x08,
135 };
136 
137 enum Http2SettingsControlFlags {
138   SETTINGS_FLAG_ACK = 0x01,
139 };
140 
141 // Wire values of HTTP/2 setting identifiers.
142 enum SpdyKnownSettingsId : SpdySettingsId {
143   // HPACK header table maximum size.
144   SETTINGS_HEADER_TABLE_SIZE = 0x1,
145   SETTINGS_MIN = SETTINGS_HEADER_TABLE_SIZE,
146   // Whether or not server push (PUSH_PROMISE) is enabled.
147   SETTINGS_ENABLE_PUSH = 0x2,
148   // The maximum number of simultaneous live streams in each direction.
149   SETTINGS_MAX_CONCURRENT_STREAMS = 0x3,
150   // Initial window size in bytes
151   SETTINGS_INITIAL_WINDOW_SIZE = 0x4,
152   // The size of the largest frame payload that a receiver is willing to accept.
153   SETTINGS_MAX_FRAME_SIZE = 0x5,
154   // The maximum size of header list that the sender is prepared to accept.
155   SETTINGS_MAX_HEADER_LIST_SIZE = 0x6,
156   // Enable Websockets over HTTP/2, see
157   // https://httpwg.org/specs/rfc8441.html
158   SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x8,
159   // Disable HTTP/2 priorities, see
160   // https://tools.ietf.org/html/draft-ietf-httpbis-priority-02.
161   SETTINGS_DEPRECATE_HTTP2_PRIORITIES = 0x9,
162   SETTINGS_MAX = SETTINGS_DEPRECATE_HTTP2_PRIORITIES,
163   // Experimental setting used to configure an alternative write scheduler.
164   SETTINGS_EXPERIMENT_SCHEDULER = 0xFF45,
165 };
166 
167 // This explicit operator is needed, otherwise compiler finds
168 // overloaded operator to be ambiguous.
169 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out,
170                                        SpdyKnownSettingsId id);
171 
172 // This operator is needed, because SpdyFrameType is an enum class,
173 // therefore implicit conversion to underlying integer type is not allowed.
174 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out,
175                                        SpdyFrameType frame_type);
176 
177 using SettingsMap = std::map<SpdySettingsId, uint32_t>;
178 
179 // HTTP/2 error codes, RFC 7540 Section 7.
180 enum SpdyErrorCode : uint32_t {
181   ERROR_CODE_NO_ERROR = 0x0,
182   ERROR_CODE_PROTOCOL_ERROR = 0x1,
183   ERROR_CODE_INTERNAL_ERROR = 0x2,
184   ERROR_CODE_FLOW_CONTROL_ERROR = 0x3,
185   ERROR_CODE_SETTINGS_TIMEOUT = 0x4,
186   ERROR_CODE_STREAM_CLOSED = 0x5,
187   ERROR_CODE_FRAME_SIZE_ERROR = 0x6,
188   ERROR_CODE_REFUSED_STREAM = 0x7,
189   ERROR_CODE_CANCEL = 0x8,
190   ERROR_CODE_COMPRESSION_ERROR = 0x9,
191   ERROR_CODE_CONNECT_ERROR = 0xa,
192   ERROR_CODE_ENHANCE_YOUR_CALM = 0xb,
193   ERROR_CODE_INADEQUATE_SECURITY = 0xc,
194   ERROR_CODE_HTTP_1_1_REQUIRED = 0xd,
195   ERROR_CODE_MAX = ERROR_CODE_HTTP_1_1_REQUIRED
196 };
197 
198 // Type of priority write scheduler.
199 enum class WriteSchedulerType {
200   LIFO,  // Last added stream has the highest priority.
201   SPDY,  // Uses SPDY priorities described in
202          // https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1#TOC-2.3.3-Stream-priority.
203   HTTP2,  // Uses HTTP2 (tree-style) priority described in
204           // https://tools.ietf.org/html/rfc7540#section-5.3.
205   FIFO,   // Stream with the smallest stream ID has the highest priority.
206 };
207 
208 // A SPDY priority is a number between 0 and 7 (inclusive).
209 typedef uint8_t SpdyPriority;
210 
211 // Lowest and Highest here refer to SPDY priorities as described in
212 // https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1#TOC-2.3.3-Stream-priority
213 inline constexpr SpdyPriority kV3HighestPriority = 0;
214 inline constexpr SpdyPriority kV3LowestPriority = 7;
215 
216 // Returns SPDY 3.x priority value clamped to the valid range of [0, 7].
217 QUICHE_EXPORT SpdyPriority ClampSpdy3Priority(SpdyPriority priority);
218 
219 // HTTP/2 stream weights are integers in range [1, 256], as specified in RFC
220 // 7540 section 5.3.2. Default stream weight is defined in section 5.3.5.
221 inline constexpr int kHttp2MinStreamWeight = 1;
222 inline constexpr int kHttp2MaxStreamWeight = 256;
223 inline constexpr int kHttp2DefaultStreamWeight = 16;
224 
225 // Returns HTTP/2 weight clamped to the valid range of [1, 256].
226 QUICHE_EXPORT int ClampHttp2Weight(int weight);
227 
228 // Maps SPDY 3.x priority value in range [0, 7] to HTTP/2 weight value in range
229 // [1, 256], where priority 0 (i.e. highest precedence) corresponds to maximum
230 // weight 256 and priority 7 (lowest precedence) corresponds to minimum weight
231 // 1.
232 QUICHE_EXPORT int Spdy3PriorityToHttp2Weight(SpdyPriority priority);
233 
234 // Maps HTTP/2 weight value in range [1, 256] to SPDY 3.x priority value in
235 // range [0, 7], where minimum weight 1 corresponds to priority 7 (lowest
236 // precedence) and maximum weight 256 corresponds to priority 0 (highest
237 // precedence).
238 QUICHE_EXPORT SpdyPriority Http2WeightToSpdy3Priority(int weight);
239 
240 // Reserved ID for root stream of HTTP/2 stream dependency tree, as specified
241 // in RFC 7540 section 5.3.1.
242 const unsigned int kHttp2RootStreamId = 0;
243 
244 typedef uint64_t SpdyPingId;
245 
246 // Returns true if a given on-the-wire enumeration of a frame type is defined
247 // in a standardized HTTP/2 specification, false otherwise.
248 QUICHE_EXPORT bool IsDefinedFrameType(uint8_t frame_type_field);
249 
250 // Parses a frame type from an on-the-wire enumeration.
251 // Behavior is undefined for invalid frame type fields; consumers should first
252 // use IsValidFrameType() to verify validity of frame type fields.
253 QUICHE_EXPORT SpdyFrameType ParseFrameType(uint8_t frame_type_field);
254 
255 // Serializes a frame type to the on-the-wire value.
256 QUICHE_EXPORT uint8_t SerializeFrameType(SpdyFrameType frame_type);
257 
258 // (HTTP/2) All standard frame types except WINDOW_UPDATE are
259 // (stream-specific xor connection-level). Returns false iff we know
260 // the given frame type does not align with the given streamID.
261 QUICHE_EXPORT bool IsValidHTTP2FrameStreamId(
262     SpdyStreamId current_frame_stream_id, SpdyFrameType frame_type_field);
263 
264 // Serialize |frame_type| to string for logging/debugging.
265 QUICHE_EXPORT const char* FrameTypeToString(SpdyFrameType frame_type);
266 
267 // If |wire_setting_id| is the on-the-wire representation of a defined SETTINGS
268 // parameter, parse it to |*setting_id| and return true.
269 QUICHE_EXPORT bool ParseSettingsId(SpdySettingsId wire_setting_id,
270                                    SpdyKnownSettingsId* setting_id);
271 
272 // Returns a string representation of the |id| for logging/debugging. Returns
273 // the |id| prefixed with "SETTINGS_UNKNOWN_" for unknown SETTINGS IDs. To parse
274 // the |id| into a SpdyKnownSettingsId (if applicable), use ParseSettingsId().
275 QUICHE_EXPORT std::string SettingsIdToString(SpdySettingsId id);
276 
277 // Parse |wire_error_code| to a SpdyErrorCode.
278 // Treat unrecognized error codes as INTERNAL_ERROR
279 // as recommended by the HTTP/2 specification.
280 QUICHE_EXPORT SpdyErrorCode ParseErrorCode(uint32_t wire_error_code);
281 
282 // Serialize RST_STREAM or GOAWAY frame error code to string
283 // for logging/debugging.
284 QUICHE_EXPORT const char* ErrorCodeToString(SpdyErrorCode error_code);
285 
286 // Serialize |type| to string for logging/debugging.
287 QUICHE_EXPORT const char* WriteSchedulerTypeToString(WriteSchedulerType type);
288 
289 // Minimum size of a frame, in octets.
290 inline constexpr size_t kFrameMinimumSize = kFrameHeaderSize;
291 
292 // Minimum frame size for variable size frame types (includes mandatory fields),
293 // frame size for fixed size frames, in octets.
294 
295 inline constexpr size_t kDataFrameMinimumSize = kFrameHeaderSize;
296 inline constexpr size_t kHeadersFrameMinimumSize = kFrameHeaderSize;
297 // PRIORITY frame has stream_dependency (4 octets) and weight (1 octet) fields.
298 inline constexpr size_t kPriorityFrameSize = kFrameHeaderSize + 5;
299 // RST_STREAM frame has error_code (4 octets) field.
300 inline constexpr size_t kRstStreamFrameSize = kFrameHeaderSize + 4;
301 inline constexpr size_t kSettingsFrameMinimumSize = kFrameHeaderSize;
302 inline constexpr size_t kSettingsOneSettingSize =
303     sizeof(uint32_t) + sizeof(SpdySettingsId);
304 // PUSH_PROMISE frame has promised_stream_id (4 octet) field.
305 inline constexpr size_t kPushPromiseFrameMinimumSize = kFrameHeaderSize + 4;
306 // PING frame has opaque_bytes (8 octet) field.
307 inline constexpr size_t kPingFrameSize = kFrameHeaderSize + 8;
308 // GOAWAY frame has last_stream_id (4 octet) and error_code (4 octet) fields.
309 inline constexpr size_t kGoawayFrameMinimumSize = kFrameHeaderSize + 8;
310 // WINDOW_UPDATE frame has window_size_increment (4 octet) field.
311 inline constexpr size_t kWindowUpdateFrameSize = kFrameHeaderSize + 4;
312 inline constexpr size_t kContinuationFrameMinimumSize = kFrameHeaderSize;
313 // ALTSVC frame has origin_len (2 octets) field.
314 inline constexpr size_t kGetAltSvcFrameMinimumSize = kFrameHeaderSize + 2;
315 // PRIORITY_UPDATE frame has prioritized_stream_id (4 octets) field.
316 inline constexpr size_t kPriorityUpdateFrameMinimumSize = kFrameHeaderSize + 4;
317 // ACCEPT_CH frame may have empty payload.
318 inline constexpr size_t kAcceptChFrameMinimumSize = kFrameHeaderSize;
319 // Each ACCEPT_CH frame entry has a 16-bit origin length and a 16-bit value
320 // length.
321 inline constexpr size_t kAcceptChFramePerEntryOverhead = 4;
322 
323 // Maximum possible configurable size of a frame in octets.
324 inline constexpr size_t kMaxFrameSizeLimit =
325     kSpdyMaxFrameSizeLimit + kFrameHeaderSize;
326 // Size of a header block size field.
327 inline constexpr size_t kSizeOfSizeField = sizeof(uint32_t);
328 // Initial window size for a stream in bytes.
329 inline constexpr int32_t kInitialStreamWindowSize = 64 * 1024 - 1;
330 // Initial window size for a session in bytes.
331 inline constexpr int32_t kInitialSessionWindowSize = 64 * 1024 - 1;
332 // The NPN string for HTTP2, "h2".
333 QUICHE_EXPORT extern const char* const kHttp2Npn;
334 // An estimate size of the HPACK overhead for each header field. 1 bytes for
335 // indexed literal, 1 bytes for key literal and length encoding, and 2 bytes for
336 // value literal and length encoding.
337 inline constexpr size_t kPerHeaderHpackOverhead = 4;
338 
339 // Names of pseudo-headers defined for HTTP/2 requests.
340 QUICHE_EXPORT extern const char* const kHttp2AuthorityHeader;
341 QUICHE_EXPORT extern const char* const kHttp2MethodHeader;
342 QUICHE_EXPORT extern const char* const kHttp2PathHeader;
343 QUICHE_EXPORT extern const char* const kHttp2SchemeHeader;
344 QUICHE_EXPORT extern const char* const kHttp2ProtocolHeader;
345 
346 // Name of pseudo-header defined for HTTP/2 responses.
347 QUICHE_EXPORT extern const char* const kHttp2StatusHeader;
348 
349 QUICHE_EXPORT size_t GetNumberRequiredContinuationFrames(size_t size);
350 
351 // Variant type that is either a SPDY 3.x priority value, or else an HTTP/2
352 // stream dependency tuple {parent stream ID, weight, exclusive bit}. Templated
353 // to allow for use by QUIC code; SPDY and HTTP/2 code should use the concrete
354 // type instantiation SpdyStreamPrecedence.
355 template <typename StreamIdType>
356 class QUICHE_EXPORT StreamPrecedence {
357  public:
358   // Constructs instance that is a SPDY 3.x priority. Clamps priority value to
359   // the valid range [0, 7].
StreamPrecedence(SpdyPriority priority)360   explicit StreamPrecedence(SpdyPriority priority)
361       : precedence_(ClampSpdy3Priority(priority)) {}
362 
363   // Constructs instance that is an HTTP/2 stream weight, parent stream ID, and
364   // exclusive bit. Clamps stream weight to the valid range [1, 256].
StreamPrecedence(StreamIdType parent_id,int weight,bool is_exclusive)365   StreamPrecedence(StreamIdType parent_id, int weight, bool is_exclusive)
366       : precedence_(Http2StreamDependency{parent_id, ClampHttp2Weight(weight),
367                                           is_exclusive}) {}
368 
369   // Intentionally copyable, to support pass by value.
370   StreamPrecedence(const StreamPrecedence& other) = default;
371   StreamPrecedence& operator=(const StreamPrecedence& other) = default;
372 
373   // Returns true if this instance is a SPDY 3.x priority, or false if this
374   // instance is an HTTP/2 stream dependency.
is_spdy3_priority()375   bool is_spdy3_priority() const {
376     return absl::holds_alternative<SpdyPriority>(precedence_);
377   }
378 
379   // Returns SPDY 3.x priority value. If |is_spdy3_priority()| is true, this is
380   // the value provided at construction, clamped to the legal priority
381   // range. Otherwise, it is the HTTP/2 stream weight mapped to a SPDY 3.x
382   // priority value, where minimum weight 1 corresponds to priority 7 (lowest
383   // precedence) and maximum weight 256 corresponds to priority 0 (highest
384   // precedence).
spdy3_priority()385   SpdyPriority spdy3_priority() const {
386     return is_spdy3_priority()
387                ? absl::get<SpdyPriority>(precedence_)
388                : Http2WeightToSpdy3Priority(
389                      absl::get<Http2StreamDependency>(precedence_).weight);
390   }
391 
392   // Returns HTTP/2 parent stream ID. If |is_spdy3_priority()| is false, this is
393   // the value provided at construction, otherwise it is |kHttp2RootStreamId|.
parent_id()394   StreamIdType parent_id() const {
395     return is_spdy3_priority()
396                ? kHttp2RootStreamId
397                : absl::get<Http2StreamDependency>(precedence_).parent_id;
398   }
399 
400   // Returns HTTP/2 stream weight. If |is_spdy3_priority()| is false, this is
401   // the value provided at construction, clamped to the legal weight
402   // range. Otherwise, it is the SPDY 3.x priority value mapped to an HTTP/2
403   // stream weight, where priority 0 (i.e. highest precedence) corresponds to
404   // maximum weight 256 and priority 7 (lowest precedence) corresponds to
405   // minimum weight 1.
weight()406   int weight() const {
407     return is_spdy3_priority()
408                ? Spdy3PriorityToHttp2Weight(
409                      absl::get<SpdyPriority>(precedence_))
410                : absl::get<Http2StreamDependency>(precedence_).weight;
411   }
412 
413   // Returns HTTP/2 parent stream exclusivity. If |is_spdy3_priority()| is
414   // false, this is the value provided at construction, otherwise it is false.
is_exclusive()415   bool is_exclusive() const {
416     return absl::holds_alternative<Http2StreamDependency>(precedence_) &&
417            absl::get<Http2StreamDependency>(precedence_).is_exclusive;
418   }
419 
420   // Facilitates test assertions.
421   bool operator==(const StreamPrecedence& other) const {
422     return precedence_ == other.precedence_;
423   }
424 
425   bool operator!=(const StreamPrecedence& other) const {
426     return !(*this == other);
427   }
428 
429  private:
430   struct QUICHE_EXPORT Http2StreamDependency {
431     StreamIdType parent_id;
432     int weight;
433     bool is_exclusive;
434 
435     bool operator==(const Http2StreamDependency& other) const {
436       return parent_id == other.parent_id && weight == other.weight &&
437              is_exclusive == other.is_exclusive;
438     }
439   };
440 
441   absl::variant<SpdyPriority, Http2StreamDependency> precedence_;
442 };
443 
444 typedef StreamPrecedence<SpdyStreamId> SpdyStreamPrecedence;
445 
446 class SpdyFrameVisitor;
447 
448 // Intermediate representation for HTTP2 frames.
449 class QUICHE_EXPORT SpdyFrameIR {
450  public:
~SpdyFrameIR()451   virtual ~SpdyFrameIR() {}
452 
453   virtual void Visit(SpdyFrameVisitor* visitor) const = 0;
454   virtual SpdyFrameType frame_type() const = 0;
stream_id()455   SpdyStreamId stream_id() const { return stream_id_; }
456   virtual bool fin() const;
457   // Returns an estimate of the size of the serialized frame, without applying
458   // compression. May not be exact.
459   virtual size_t size() const = 0;
460 
461   // Returns the number of bytes of flow control window that would be consumed
462   // by this frame if written to the wire.
463   virtual int flow_control_window_consumed() const;
464 
465  protected:
SpdyFrameIR()466   SpdyFrameIR() : stream_id_(0) {}
SpdyFrameIR(SpdyStreamId stream_id)467   explicit SpdyFrameIR(SpdyStreamId stream_id) : stream_id_(stream_id) {}
468   SpdyFrameIR(const SpdyFrameIR&) = delete;
469   SpdyFrameIR& operator=(const SpdyFrameIR&) = delete;
470 
471  private:
472   SpdyStreamId stream_id_;
473 };
474 
475 // Abstract class intended to be inherited by IRs that have the option of a FIN
476 // flag.
477 class QUICHE_EXPORT SpdyFrameWithFinIR : public SpdyFrameIR {
478  public:
~SpdyFrameWithFinIR()479   ~SpdyFrameWithFinIR() override {}
480   bool fin() const override;
set_fin(bool fin)481   void set_fin(bool fin) { fin_ = fin; }
482 
483  protected:
SpdyFrameWithFinIR(SpdyStreamId stream_id)484   explicit SpdyFrameWithFinIR(SpdyStreamId stream_id)
485       : SpdyFrameIR(stream_id), fin_(false) {}
486   SpdyFrameWithFinIR(const SpdyFrameWithFinIR&) = delete;
487   SpdyFrameWithFinIR& operator=(const SpdyFrameWithFinIR&) = delete;
488 
489  private:
490   bool fin_;
491 };
492 
493 // Abstract class intended to be inherited by IRs that contain a header
494 // block. Implies SpdyFrameWithFinIR.
495 class QUICHE_EXPORT SpdyFrameWithHeaderBlockIR : public SpdyFrameWithFinIR {
496  public:
497   ~SpdyFrameWithHeaderBlockIR() override;
498 
header_block()499   const Http2HeaderBlock& header_block() const { return header_block_; }
set_header_block(Http2HeaderBlock header_block)500   void set_header_block(Http2HeaderBlock header_block) {
501     // Deep copy.
502     header_block_ = std::move(header_block);
503   }
SetHeader(absl::string_view name,absl::string_view value)504   void SetHeader(absl::string_view name, absl::string_view value) {
505     header_block_[name] = value;
506   }
507 
508  protected:
509   SpdyFrameWithHeaderBlockIR(SpdyStreamId stream_id,
510                              Http2HeaderBlock header_block);
511   SpdyFrameWithHeaderBlockIR(const SpdyFrameWithHeaderBlockIR&) = delete;
512   SpdyFrameWithHeaderBlockIR& operator=(const SpdyFrameWithHeaderBlockIR&) =
513       delete;
514 
515  private:
516   Http2HeaderBlock header_block_;
517 };
518 
519 class QUICHE_EXPORT SpdyDataIR : public SpdyFrameWithFinIR {
520  public:
521   // Performs a deep copy on data.
522   SpdyDataIR(SpdyStreamId stream_id, absl::string_view data);
523 
524   // Performs a deep copy on data.
525   SpdyDataIR(SpdyStreamId stream_id, const char* data);
526 
527   // Moves data into data_store_. Makes a copy if passed a non-movable string.
528   SpdyDataIR(SpdyStreamId stream_id, std::string data);
529 
530   // Use in conjunction with SetDataShallow() for shallow-copy on data.
531   explicit SpdyDataIR(SpdyStreamId stream_id);
532   SpdyDataIR(const SpdyDataIR&) = delete;
533   SpdyDataIR& operator=(const SpdyDataIR&) = delete;
534 
535   ~SpdyDataIR() override;
536 
data()537   const char* data() const { return data_; }
data_len()538   size_t data_len() const { return data_len_; }
539 
padded()540   bool padded() const { return padded_; }
541 
padding_payload_len()542   int padding_payload_len() const { return padding_payload_len_; }
543 
set_padding_len(int padding_len)544   void set_padding_len(int padding_len) {
545     QUICHE_DCHECK_GT(padding_len, 0);
546     QUICHE_DCHECK_LE(padding_len, kPaddingSizePerFrame);
547     padded_ = true;
548     // The pad field takes one octet on the wire.
549     padding_payload_len_ = padding_len - 1;
550   }
551 
552   // Deep-copy of data (keep private copy).
SetDataDeep(absl::string_view data)553   void SetDataDeep(absl::string_view data) {
554     data_store_ = std::make_unique<std::string>(data.data(), data.size());
555     data_ = data_store_->data();
556     data_len_ = data.size();
557   }
558 
559   // Shallow-copy of data (do not keep private copy).
SetDataShallow(absl::string_view data)560   void SetDataShallow(absl::string_view data) {
561     data_store_.reset();
562     data_ = data.data();
563     data_len_ = data.size();
564   }
565 
566   // Use this method if we don't have a contiguous buffer and only
567   // need a length.
SetDataShallow(size_t len)568   void SetDataShallow(size_t len) {
569     data_store_.reset();
570     data_ = nullptr;
571     data_len_ = len;
572   }
573 
574   void Visit(SpdyFrameVisitor* visitor) const override;
575 
576   SpdyFrameType frame_type() const override;
577 
578   int flow_control_window_consumed() const override;
579 
580   size_t size() const override;
581 
582  private:
583   // Used to store data that this SpdyDataIR should own.
584   std::unique_ptr<std::string> data_store_;
585   const char* data_;
586   size_t data_len_;
587 
588   bool padded_;
589   // padding_payload_len_ = desired padding length - len(padding length field).
590   int padding_payload_len_;
591 };
592 
593 class QUICHE_EXPORT SpdyRstStreamIR : public SpdyFrameIR {
594  public:
595   SpdyRstStreamIR(SpdyStreamId stream_id, SpdyErrorCode error_code);
596   SpdyRstStreamIR(const SpdyRstStreamIR&) = delete;
597   SpdyRstStreamIR& operator=(const SpdyRstStreamIR&) = delete;
598 
599   ~SpdyRstStreamIR() override;
600 
error_code()601   SpdyErrorCode error_code() const { return error_code_; }
set_error_code(SpdyErrorCode error_code)602   void set_error_code(SpdyErrorCode error_code) { error_code_ = error_code; }
603 
604   void Visit(SpdyFrameVisitor* visitor) const override;
605 
606   SpdyFrameType frame_type() const override;
607 
608   size_t size() const override;
609 
610  private:
611   SpdyErrorCode error_code_;
612 };
613 
614 class QUICHE_EXPORT SpdySettingsIR : public SpdyFrameIR {
615  public:
616   SpdySettingsIR();
617   SpdySettingsIR(const SpdySettingsIR&) = delete;
618   SpdySettingsIR& operator=(const SpdySettingsIR&) = delete;
619   ~SpdySettingsIR() override;
620 
621   // Overwrites as appropriate.
values()622   const SettingsMap& values() const { return values_; }
AddSetting(SpdySettingsId id,int32_t value)623   void AddSetting(SpdySettingsId id, int32_t value) { values_[id] = value; }
624 
is_ack()625   bool is_ack() const { return is_ack_; }
set_is_ack(bool is_ack)626   void set_is_ack(bool is_ack) { is_ack_ = is_ack; }
627 
628   void Visit(SpdyFrameVisitor* visitor) const override;
629 
630   SpdyFrameType frame_type() const override;
631 
632   size_t size() const override;
633 
634  private:
635   SettingsMap values_;
636   bool is_ack_;
637 };
638 
639 class QUICHE_EXPORT SpdyPingIR : public SpdyFrameIR {
640  public:
SpdyPingIR(SpdyPingId id)641   explicit SpdyPingIR(SpdyPingId id) : id_(id), is_ack_(false) {}
642   SpdyPingIR(const SpdyPingIR&) = delete;
643   SpdyPingIR& operator=(const SpdyPingIR&) = delete;
id()644   SpdyPingId id() const { return id_; }
645 
is_ack()646   bool is_ack() const { return is_ack_; }
set_is_ack(bool is_ack)647   void set_is_ack(bool is_ack) { is_ack_ = is_ack; }
648 
649   void Visit(SpdyFrameVisitor* visitor) const override;
650 
651   SpdyFrameType frame_type() const override;
652 
653   size_t size() const override;
654 
655  private:
656   SpdyPingId id_;
657   bool is_ack_;
658 };
659 
660 class QUICHE_EXPORT SpdyGoAwayIR : public SpdyFrameIR {
661  public:
662   // References description, doesn't copy it, so description must outlast
663   // this SpdyGoAwayIR.
664   SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyErrorCode error_code,
665                absl::string_view description);
666 
667   // References description, doesn't copy it, so description must outlast
668   // this SpdyGoAwayIR.
669   SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyErrorCode error_code,
670                const char* description);
671 
672   // Moves description into description_store_, so caller doesn't need to
673   // keep description live after constructing this SpdyGoAwayIR.
674   SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyErrorCode error_code,
675                std::string description);
676   SpdyGoAwayIR(const SpdyGoAwayIR&) = delete;
677   SpdyGoAwayIR& operator=(const SpdyGoAwayIR&) = delete;
678 
679   ~SpdyGoAwayIR() override;
680 
last_good_stream_id()681   SpdyStreamId last_good_stream_id() const { return last_good_stream_id_; }
set_last_good_stream_id(SpdyStreamId last_good_stream_id)682   void set_last_good_stream_id(SpdyStreamId last_good_stream_id) {
683     QUICHE_DCHECK_EQ(0u, last_good_stream_id & ~kStreamIdMask);
684     last_good_stream_id_ = last_good_stream_id;
685   }
error_code()686   SpdyErrorCode error_code() const { return error_code_; }
set_error_code(SpdyErrorCode error_code)687   void set_error_code(SpdyErrorCode error_code) {
688     // TODO(hkhalil): Check valid ranges of error_code?
689     error_code_ = error_code;
690   }
691 
description()692   const absl::string_view& description() const { return description_; }
693 
694   void Visit(SpdyFrameVisitor* visitor) const override;
695 
696   SpdyFrameType frame_type() const override;
697 
698   size_t size() const override;
699 
700  private:
701   SpdyStreamId last_good_stream_id_;
702   SpdyErrorCode error_code_;
703   const std::string description_store_;
704   const absl::string_view description_;
705 };
706 
707 class QUICHE_EXPORT SpdyHeadersIR : public SpdyFrameWithHeaderBlockIR {
708  public:
SpdyHeadersIR(SpdyStreamId stream_id)709   explicit SpdyHeadersIR(SpdyStreamId stream_id)
710       : SpdyHeadersIR(stream_id, Http2HeaderBlock()) {}
SpdyHeadersIR(SpdyStreamId stream_id,Http2HeaderBlock header_block)711   SpdyHeadersIR(SpdyStreamId stream_id, Http2HeaderBlock header_block)
712       : SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)) {}
713   SpdyHeadersIR(const SpdyHeadersIR&) = delete;
714   SpdyHeadersIR& operator=(const SpdyHeadersIR&) = delete;
715 
716   void Visit(SpdyFrameVisitor* visitor) const override;
717 
718   SpdyFrameType frame_type() const override;
719 
720   size_t size() const override;
721 
has_priority()722   bool has_priority() const { return has_priority_; }
set_has_priority(bool has_priority)723   void set_has_priority(bool has_priority) { has_priority_ = has_priority; }
weight()724   int weight() const { return weight_; }
set_weight(int weight)725   void set_weight(int weight) { weight_ = weight; }
parent_stream_id()726   SpdyStreamId parent_stream_id() const { return parent_stream_id_; }
set_parent_stream_id(SpdyStreamId id)727   void set_parent_stream_id(SpdyStreamId id) { parent_stream_id_ = id; }
exclusive()728   bool exclusive() const { return exclusive_; }
set_exclusive(bool exclusive)729   void set_exclusive(bool exclusive) { exclusive_ = exclusive; }
padded()730   bool padded() const { return padded_; }
padding_payload_len()731   int padding_payload_len() const { return padding_payload_len_; }
set_padding_len(int padding_len)732   void set_padding_len(int padding_len) {
733     QUICHE_DCHECK_GT(padding_len, 0);
734     QUICHE_DCHECK_LE(padding_len, kPaddingSizePerFrame);
735     padded_ = true;
736     // The pad field takes one octet on the wire.
737     padding_payload_len_ = padding_len - 1;
738   }
739 
740  private:
741   bool has_priority_ = false;
742   int weight_ = kHttp2DefaultStreamWeight;
743   SpdyStreamId parent_stream_id_ = 0;
744   bool exclusive_ = false;
745   bool padded_ = false;
746   int padding_payload_len_ = 0;
747 };
748 
749 class QUICHE_EXPORT SpdyWindowUpdateIR : public SpdyFrameIR {
750  public:
SpdyWindowUpdateIR(SpdyStreamId stream_id,int32_t delta)751   SpdyWindowUpdateIR(SpdyStreamId stream_id, int32_t delta)
752       : SpdyFrameIR(stream_id) {
753     set_delta(delta);
754   }
755   SpdyWindowUpdateIR(const SpdyWindowUpdateIR&) = delete;
756   SpdyWindowUpdateIR& operator=(const SpdyWindowUpdateIR&) = delete;
757 
delta()758   int32_t delta() const { return delta_; }
set_delta(int32_t delta)759   void set_delta(int32_t delta) {
760     QUICHE_DCHECK_LE(0, delta);
761     QUICHE_DCHECK_LE(delta, kSpdyMaximumWindowSize);
762     delta_ = delta;
763   }
764 
765   void Visit(SpdyFrameVisitor* visitor) const override;
766 
767   SpdyFrameType frame_type() const override;
768 
769   size_t size() const override;
770 
771  private:
772   int32_t delta_;
773 };
774 
775 class QUICHE_EXPORT SpdyPushPromiseIR : public SpdyFrameWithHeaderBlockIR {
776  public:
SpdyPushPromiseIR(SpdyStreamId stream_id,SpdyStreamId promised_stream_id)777   SpdyPushPromiseIR(SpdyStreamId stream_id, SpdyStreamId promised_stream_id)
778       : SpdyPushPromiseIR(stream_id, promised_stream_id, Http2HeaderBlock()) {}
SpdyPushPromiseIR(SpdyStreamId stream_id,SpdyStreamId promised_stream_id,Http2HeaderBlock header_block)779   SpdyPushPromiseIR(SpdyStreamId stream_id, SpdyStreamId promised_stream_id,
780                     Http2HeaderBlock header_block)
781       : SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)),
782         promised_stream_id_(promised_stream_id),
783         padded_(false),
784         padding_payload_len_(0) {}
785   SpdyPushPromiseIR(const SpdyPushPromiseIR&) = delete;
786   SpdyPushPromiseIR& operator=(const SpdyPushPromiseIR&) = delete;
promised_stream_id()787   SpdyStreamId promised_stream_id() const { return promised_stream_id_; }
788 
789   void Visit(SpdyFrameVisitor* visitor) const override;
790 
791   SpdyFrameType frame_type() const override;
792 
793   size_t size() const override;
794 
padded()795   bool padded() const { return padded_; }
padding_payload_len()796   int padding_payload_len() const { return padding_payload_len_; }
set_padding_len(int padding_len)797   void set_padding_len(int padding_len) {
798     QUICHE_DCHECK_GT(padding_len, 0);
799     QUICHE_DCHECK_LE(padding_len, kPaddingSizePerFrame);
800     padded_ = true;
801     // The pad field takes one octet on the wire.
802     padding_payload_len_ = padding_len - 1;
803   }
804 
805  private:
806   SpdyStreamId promised_stream_id_;
807 
808   bool padded_;
809   int padding_payload_len_;
810 };
811 
812 class QUICHE_EXPORT SpdyContinuationIR : public SpdyFrameIR {
813  public:
814   explicit SpdyContinuationIR(SpdyStreamId stream_id);
815   SpdyContinuationIR(const SpdyContinuationIR&) = delete;
816   SpdyContinuationIR& operator=(const SpdyContinuationIR&) = delete;
817   ~SpdyContinuationIR() override;
818 
819   void Visit(SpdyFrameVisitor* visitor) const override;
820 
821   SpdyFrameType frame_type() const override;
822 
end_headers()823   bool end_headers() const { return end_headers_; }
set_end_headers(bool end_headers)824   void set_end_headers(bool end_headers) { end_headers_ = end_headers; }
encoding()825   const std::string& encoding() const { return encoding_; }
take_encoding(std::string encoding)826   void take_encoding(std::string encoding) { encoding_ = std::move(encoding); }
827   size_t size() const override;
828 
829  private:
830   std::string encoding_;
831   bool end_headers_;
832 };
833 
834 class QUICHE_EXPORT SpdyAltSvcIR : public SpdyFrameIR {
835  public:
836   explicit SpdyAltSvcIR(SpdyStreamId stream_id);
837   SpdyAltSvcIR(const SpdyAltSvcIR&) = delete;
838   SpdyAltSvcIR& operator=(const SpdyAltSvcIR&) = delete;
839   ~SpdyAltSvcIR() override;
840 
origin()841   std::string origin() const { return origin_; }
altsvc_vector()842   const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector() const {
843     return altsvc_vector_;
844   }
845 
set_origin(std::string origin)846   void set_origin(std::string origin) { origin_ = std::move(origin); }
add_altsvc(const SpdyAltSvcWireFormat::AlternativeService & altsvc)847   void add_altsvc(const SpdyAltSvcWireFormat::AlternativeService& altsvc) {
848     altsvc_vector_.push_back(altsvc);
849   }
850 
851   void Visit(SpdyFrameVisitor* visitor) const override;
852 
853   SpdyFrameType frame_type() const override;
854 
855   size_t size() const override;
856 
857  private:
858   std::string origin_;
859   SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_;
860 };
861 
862 class QUICHE_EXPORT SpdyPriorityIR : public SpdyFrameIR {
863  public:
SpdyPriorityIR(SpdyStreamId stream_id,SpdyStreamId parent_stream_id,int weight,bool exclusive)864   SpdyPriorityIR(SpdyStreamId stream_id, SpdyStreamId parent_stream_id,
865                  int weight, bool exclusive)
866       : SpdyFrameIR(stream_id),
867         parent_stream_id_(parent_stream_id),
868         weight_(weight),
869         exclusive_(exclusive) {}
870   SpdyPriorityIR(const SpdyPriorityIR&) = delete;
871   SpdyPriorityIR& operator=(const SpdyPriorityIR&) = delete;
parent_stream_id()872   SpdyStreamId parent_stream_id() const { return parent_stream_id_; }
weight()873   int weight() const { return weight_; }
exclusive()874   bool exclusive() const { return exclusive_; }
875 
876   void Visit(SpdyFrameVisitor* visitor) const override;
877 
878   SpdyFrameType frame_type() const override;
879 
880   size_t size() const override;
881 
882  private:
883   SpdyStreamId parent_stream_id_;
884   int weight_;
885   bool exclusive_;
886 };
887 
888 class QUICHE_EXPORT SpdyPriorityUpdateIR : public SpdyFrameIR {
889  public:
SpdyPriorityUpdateIR(SpdyStreamId stream_id,SpdyStreamId prioritized_stream_id,std::string priority_field_value)890   SpdyPriorityUpdateIR(SpdyStreamId stream_id,
891                        SpdyStreamId prioritized_stream_id,
892                        std::string priority_field_value)
893       : SpdyFrameIR(stream_id),
894         prioritized_stream_id_(prioritized_stream_id),
895         priority_field_value_(std::move(priority_field_value)) {}
896   SpdyPriorityUpdateIR(const SpdyPriorityUpdateIR&) = delete;
897   SpdyPriorityUpdateIR& operator=(const SpdyPriorityUpdateIR&) = delete;
prioritized_stream_id()898   SpdyStreamId prioritized_stream_id() const { return prioritized_stream_id_; }
priority_field_value()899   const std::string& priority_field_value() const {
900     return priority_field_value_;
901   }
902 
903   void Visit(SpdyFrameVisitor* visitor) const override;
904 
905   SpdyFrameType frame_type() const override;
906 
907   size_t size() const override;
908 
909  private:
910   SpdyStreamId prioritized_stream_id_;
911   std::string priority_field_value_;
912 };
913 
914 struct QUICHE_EXPORT AcceptChOriginValuePair {
915   std::string origin;
916   std::string value;
917   bool operator==(const AcceptChOriginValuePair& rhs) const {
918     return origin == rhs.origin && value == rhs.value;
919   }
920 };
921 
922 class QUICHE_EXPORT SpdyAcceptChIR : public SpdyFrameIR {
923  public:
SpdyAcceptChIR(std::vector<AcceptChOriginValuePair> entries)924   SpdyAcceptChIR(std::vector<AcceptChOriginValuePair> entries)
925       : entries_(std::move(entries)) {}
926   SpdyAcceptChIR(const SpdyAcceptChIR&) = delete;
927   SpdyAcceptChIR& operator=(const SpdyAcceptChIR&) = delete;
928 
929   void Visit(SpdyFrameVisitor* visitor) const override;
930 
931   SpdyFrameType frame_type() const override;
932 
933   size_t size() const override;
934 
entries()935   const std::vector<AcceptChOriginValuePair>& entries() const {
936     return entries_;
937   }
938 
939  private:
940   std::vector<AcceptChOriginValuePair> entries_;
941 };
942 
943 // Represents a frame of unrecognized type.
944 class QUICHE_EXPORT SpdyUnknownIR : public SpdyFrameIR {
945  public:
SpdyUnknownIR(SpdyStreamId stream_id,uint8_t type,uint8_t flags,std::string payload)946   SpdyUnknownIR(SpdyStreamId stream_id, uint8_t type, uint8_t flags,
947                 std::string payload)
948       : SpdyFrameIR(stream_id),
949         type_(type),
950         flags_(flags),
951         length_(payload.size()),
952         payload_(std::move(payload)) {}
953   SpdyUnknownIR(const SpdyUnknownIR&) = delete;
954   SpdyUnknownIR& operator=(const SpdyUnknownIR&) = delete;
type()955   uint8_t type() const { return type_; }
flags()956   uint8_t flags() const { return flags_; }
length()957   size_t length() const { return length_; }
payload()958   const std::string& payload() const { return payload_; }
959 
960   void Visit(SpdyFrameVisitor* visitor) const override;
961 
962   SpdyFrameType frame_type() const override;
963 
964   int flow_control_window_consumed() const override;
965 
966   size_t size() const override;
967 
968  protected:
969   // Allows subclasses to overwrite the default payload length.
set_length(size_t length)970   void set_length(size_t length) { length_ = length; }
971 
972  private:
973   uint8_t type_;
974   uint8_t flags_;
975   size_t length_;
976   const std::string payload_;
977 };
978 
979 class QUICHE_EXPORT SpdySerializedFrame {
980  public:
SpdySerializedFrame()981   SpdySerializedFrame()
982       : frame_(const_cast<char*>("")), size_(0), owns_buffer_(false) {}
983 
984   // Create a valid SpdySerializedFrame using a pre-created buffer.
985   // If |owns_buffer| is true, this class takes ownership of the buffer and will
986   // delete it on cleanup.  The buffer must have been created using new char[].
987   // If |owns_buffer| is false, the caller retains ownership of the buffer and
988   // is responsible for making sure the buffer outlives this frame.  In other
989   // words, this class does NOT create a copy of the buffer.
SpdySerializedFrame(char * data,size_t size,bool owns_buffer)990   SpdySerializedFrame(char* data, size_t size, bool owns_buffer)
991       : frame_(data), size_(size), owns_buffer_(owns_buffer) {}
992 
SpdySerializedFrame(SpdySerializedFrame && other)993   SpdySerializedFrame(SpdySerializedFrame&& other)
994       : frame_(other.frame_),
995         size_(other.size_),
996         owns_buffer_(other.owns_buffer_) {
997     // |other| is no longer responsible for the buffer.
998     other.owns_buffer_ = false;
999   }
1000   SpdySerializedFrame(const SpdySerializedFrame&) = delete;
1001   SpdySerializedFrame& operator=(const SpdySerializedFrame&) = delete;
1002 
1003   SpdySerializedFrame& operator=(SpdySerializedFrame&& other) {
1004     // Free buffer if necessary.
1005     if (owns_buffer_) {
1006       delete[] frame_;
1007     }
1008     // Take over |other|.
1009     frame_ = other.frame_;
1010     size_ = other.size_;
1011     owns_buffer_ = other.owns_buffer_;
1012     // |other| is no longer responsible for the buffer.
1013     other.owns_buffer_ = false;
1014     return *this;
1015   }
1016 
~SpdySerializedFrame()1017   ~SpdySerializedFrame() {
1018     if (owns_buffer_) {
1019       delete[] frame_;
1020     }
1021   }
1022 
1023   // Provides access to the frame bytes, which is a buffer containing the frame
1024   // packed as expected for sending over the wire.
data()1025   char* data() const { return frame_; }
1026 
1027   // Returns the actual size of the underlying buffer.
size()1028   size_t size() const { return size_; }
1029 
string_view()1030   operator absl::string_view() const {
1031     return absl::string_view{frame_, size_};
1032   }
1033 
string()1034   operator std::string() const { return std::string{frame_, size_}; }
1035 
1036   // Returns a buffer containing the contents of the frame, of which the caller
1037   // takes ownership, and clears this SpdySerializedFrame.
ReleaseBuffer()1038   char* ReleaseBuffer() {
1039     char* buffer;
1040     if (owns_buffer_) {
1041       // If the buffer is owned, relinquish ownership to the caller.
1042       buffer = frame_;
1043       owns_buffer_ = false;
1044     } else {
1045       // Otherwise, we need to make a copy to give to the caller.
1046       buffer = new char[size_];
1047       memcpy(buffer, frame_, size_);
1048     }
1049     *this = SpdySerializedFrame();
1050     return buffer;
1051   }
1052 
1053  protected:
1054   char* frame_;
1055 
1056  private:
1057   size_t size_;
1058   bool owns_buffer_;
1059 };
1060 
1061 // This interface is for classes that want to process SpdyFrameIRs without
1062 // having to know what type they are.  An instance of this interface can be
1063 // passed to a SpdyFrameIR's Visit method, and the appropriate type-specific
1064 // method of this class will be called.
1065 class QUICHE_EXPORT SpdyFrameVisitor {
1066  public:
SpdyFrameVisitor()1067   SpdyFrameVisitor() {}
1068   SpdyFrameVisitor(const SpdyFrameVisitor&) = delete;
1069   SpdyFrameVisitor& operator=(const SpdyFrameVisitor&) = delete;
~SpdyFrameVisitor()1070   virtual ~SpdyFrameVisitor() {}
1071 
1072   virtual void VisitRstStream(const SpdyRstStreamIR& rst_stream) = 0;
1073   virtual void VisitSettings(const SpdySettingsIR& settings) = 0;
1074   virtual void VisitPing(const SpdyPingIR& ping) = 0;
1075   virtual void VisitGoAway(const SpdyGoAwayIR& goaway) = 0;
1076   virtual void VisitHeaders(const SpdyHeadersIR& headers) = 0;
1077   virtual void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) = 0;
1078   virtual void VisitPushPromise(const SpdyPushPromiseIR& push_promise) = 0;
1079   virtual void VisitContinuation(const SpdyContinuationIR& continuation) = 0;
1080   virtual void VisitAltSvc(const SpdyAltSvcIR& altsvc) = 0;
1081   virtual void VisitPriority(const SpdyPriorityIR& priority) = 0;
1082   virtual void VisitData(const SpdyDataIR& data) = 0;
1083   virtual void VisitPriorityUpdate(
1084       const SpdyPriorityUpdateIR& priority_update) = 0;
1085   virtual void VisitAcceptCh(const SpdyAcceptChIR& accept_ch) = 0;
VisitUnknown(const SpdyUnknownIR &)1086   virtual void VisitUnknown(const SpdyUnknownIR& /*unknown*/) {
1087     // TODO(birenroy): make abstract.
1088   }
1089 };
1090 
1091 // Optionally, and in addition to SpdyFramerVisitorInterface, a class supporting
1092 // SpdyFramerDebugVisitorInterface may be used in conjunction with SpdyFramer in
1093 // order to extract debug/internal information about the SpdyFramer as it
1094 // operates.
1095 //
1096 // Most HTTP2 implementations need not bother with this interface at all.
1097 class QUICHE_EXPORT SpdyFramerDebugVisitorInterface {
1098  public:
~SpdyFramerDebugVisitorInterface()1099   virtual ~SpdyFramerDebugVisitorInterface() {}
1100 
1101   // Called after compressing a frame with a payload of
1102   // a list of name-value pairs.
1103   // |payload_len| is the uncompressed payload size.
1104   // |frame_len| is the compressed frame size.
OnSendCompressedFrame(SpdyStreamId,SpdyFrameType,size_t,size_t)1105   virtual void OnSendCompressedFrame(SpdyStreamId /*stream_id*/,
1106                                      SpdyFrameType /*type*/,
1107                                      size_t /*payload_len*/,
1108                                      size_t /*frame_len*/) {}
1109 
1110   // Called when a frame containing a compressed payload of
1111   // name-value pairs is received.
1112   // |frame_len| is the compressed frame size.
OnReceiveCompressedFrame(SpdyStreamId,SpdyFrameType,size_t)1113   virtual void OnReceiveCompressedFrame(SpdyStreamId /*stream_id*/,
1114                                         SpdyFrameType /*type*/,
1115                                         size_t /*frame_len*/) {}
1116 };
1117 
1118 // Calculates the number of bytes required to serialize a SpdyHeadersIR, not
1119 // including the bytes to be used for the encoded header set.
1120 size_t GetHeaderFrameSizeSansBlock(const SpdyHeadersIR& header_ir);
1121 
1122 // Calculates the number of bytes required to serialize a SpdyPushPromiseIR,
1123 // not including the bytes to be used for the encoded header set.
1124 size_t GetPushPromiseFrameSizeSansBlock(
1125     const SpdyPushPromiseIR& push_promise_ir);
1126 
1127 }  // namespace spdy
1128 
1129 #endif  // QUICHE_SPDY_CORE_SPDY_PROTOCOL_H_
1130