1// Copyright (c) 2010 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.
6
7#ifndef NET_SPDY_SPDY_PROTOCOL_H_
8#define NET_SPDY_SPDY_PROTOCOL_H_
9#pragma once
10
11#include <limits>
12
13#include "base/basictypes.h"
14#include "base/logging.h"
15#include "net/base/sys_byteorder.h"
16#include "net/spdy/spdy_bitmasks.h"
17
18//  Data Frame Format
19//  +----------------------------------+
20//  |0|       Stream-ID (31bits)       |
21//  +----------------------------------+
22//  | flags (8)  |  Length (24 bits)   |
23//  +----------------------------------+
24//  |               Data               |
25//  +----------------------------------+
26//
27//  Control Frame Format
28//  +----------------------------------+
29//  |1| Version(15bits) | Type(16bits) |
30//  +----------------------------------+
31//  | flags (8)  |  Length (24 bits)   |
32//  +----------------------------------+
33//  |               Data               |
34//  +----------------------------------+
35//
36//  Control Frame: SYN_STREAM
37//  +----------------------------------+
38//  |1|000000000000001|0000000000000001|
39//  +----------------------------------+
40//  | flags (8)  |  Length (24 bits)   |  >= 12
41//  +----------------------------------+
42//  |X|       Stream-ID(31bits)        |
43//  +----------------------------------+
44//  |X|Associated-To-Stream-ID (31bits)|
45//  +----------------------------------+
46//  |Pri| unused      | Length (16bits)|
47//  +----------------------------------+
48//
49//  Control Frame: SYN_REPLY
50//  +----------------------------------+
51//  |1|000000000000001|0000000000000010|
52//  +----------------------------------+
53//  | flags (8)  |  Length (24 bits)   |  >= 8
54//  +----------------------------------+
55//  |X|       Stream-ID(31bits)        |
56//  +----------------------------------+
57//  | unused (16 bits)| Length (16bits)|
58//  +----------------------------------+
59//
60//  Control Frame: RST_STREAM
61//  +----------------------------------+
62//  |1|000000000000001|0000000000000011|
63//  +----------------------------------+
64//  | flags (8)  |  Length (24 bits)   |  >= 4
65//  +----------------------------------+
66//  |X|       Stream-ID(31bits)        |
67//  +----------------------------------+
68//  |        Status code (32 bits)     |
69//  +----------------------------------+
70//
71//  Control Frame: SETTINGS
72//  +----------------------------------+
73//  |1|000000000000001|0000000000000100|
74//  +----------------------------------+
75//  | flags (8)  |  Length (24 bits)   |
76//  +----------------------------------+
77//  |        # of entries (32)         |
78//  +----------------------------------+
79//
80//  Control Frame: NOOP
81//  +----------------------------------+
82//  |1|000000000000001|0000000000000101|
83//  +----------------------------------+
84//  | flags (8)  |  Length (24 bits)   | = 0
85//  +----------------------------------+
86//
87//  Control Frame: PING
88//  +----------------------------------+
89//  |1|000000000000001|0000000000000110|
90//  +----------------------------------+
91//  | flags (8)  |  Length (24 bits)   | = 4
92//  +----------------------------------+
93//  |        Unique id (32 bits)       |
94//  +----------------------------------+
95//
96//  Control Frame: GOAWAY
97//  +----------------------------------+
98//  |1|000000000000001|0000000000000111|
99//  +----------------------------------+
100//  | flags (8)  |  Length (24 bits)   | = 4
101//  +----------------------------------+
102//  |X|  Last-accepted-stream-id       |
103//  +----------------------------------+
104//
105//  Control Frame: HEADERS
106//  +----------------------------------+
107//  |1|000000000000001|0000000000001000|
108//  +----------------------------------+
109//  | flags (8)  |  Length (24 bits)   | >= 8
110//  +----------------------------------+
111//  |X|      Stream-ID (31 bits)       |
112//  +----------------------------------+
113//  | unused (16 bits)| Length (16bits)|
114//  +----------------------------------+
115//
116//  Control Frame: WINDOW_UPDATE
117//  +----------------------------------+
118//  |1|000000000000001|0000000000001001|
119//  +----------------------------------+
120//  | flags (8)  |  Length (24 bits)   | = 8
121//  +----------------------------------+
122//  |X|      Stream-ID (31 bits)       |
123//  +----------------------------------+
124//  |   Delta-Window-Size (32 bits)    |
125//  +----------------------------------+
126namespace spdy {
127
128// This implementation of Spdy is version 2; It's like version 1, with some
129// minor tweaks.
130const int kSpdyProtocolVersion = 2;
131
132// Initial window size for a Spdy stream
133const size_t kSpdyStreamInitialWindowSize = 64 * 1024;  // 64 KBytes
134
135// Maximum window size for a Spdy stream
136const size_t kSpdyStreamMaximumWindowSize = std::numeric_limits<int32>::max();
137
138// HTTP-over-SPDY header constants
139const char kMethod[] = "method";
140const char kStatus[] = "status";
141const char kUrl[] = "url";
142const char kVersion[] = "version";
143// When we server push, we will add [path: fully/qualified/url] to the server
144// push headers so that the client will know what url the data corresponds to.
145const char kPath[] = "path";
146
147// Note: all protocol data structures are on-the-wire format.  That means that
148//       data is stored in network-normalized order.  Readers must use the
149//       accessors provided or call ntohX() functions.
150
151// Types of Spdy Control Frames.
152enum SpdyControlType {
153  SYN_STREAM = 1,
154  SYN_REPLY,
155  RST_STREAM,
156  SETTINGS,
157  NOOP,
158  PING,
159  GOAWAY,
160  HEADERS,
161  WINDOW_UPDATE,
162  NUM_CONTROL_FRAME_TYPES
163};
164
165// Flags on data packets.
166enum SpdyDataFlags {
167  DATA_FLAG_NONE = 0,
168  DATA_FLAG_FIN = 1,
169  DATA_FLAG_COMPRESSED = 2
170};
171
172// Flags on control packets
173enum SpdyControlFlags {
174  CONTROL_FLAG_NONE = 0,
175  CONTROL_FLAG_FIN = 1,
176  CONTROL_FLAG_UNIDIRECTIONAL = 2
177};
178
179// Flags on the SETTINGS control frame.
180enum SpdySettingsControlFlags {
181  SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS = 0x1
182};
183
184// Flags for settings within a SETTINGS frame.
185enum SpdySettingsFlags {
186  SETTINGS_FLAG_PLEASE_PERSIST = 0x1,
187  SETTINGS_FLAG_PERSISTED = 0x2
188};
189
190// List of known settings.
191enum SpdySettingsIds {
192  SETTINGS_UPLOAD_BANDWIDTH = 0x1,
193  SETTINGS_DOWNLOAD_BANDWIDTH = 0x2,
194  // Network round trip time in milliseconds.
195  SETTINGS_ROUND_TRIP_TIME = 0x3,
196  SETTINGS_MAX_CONCURRENT_STREAMS = 0x4,
197  // TCP congestion window in packets.
198  SETTINGS_CURRENT_CWND = 0x5,
199  // Downstream byte retransmission rate in percentage.
200  SETTINGS_DOWNLOAD_RETRANS_RATE = 0x6,
201  // Initial window size in bytes
202  SETTINGS_INITIAL_WINDOW_SIZE = 0x7
203};
204
205// Status codes, as used in control frames (primarily RST_STREAM).
206enum SpdyStatusCodes {
207  INVALID = 0,
208  PROTOCOL_ERROR = 1,
209  INVALID_STREAM = 2,
210  REFUSED_STREAM = 3,
211  UNSUPPORTED_VERSION = 4,
212  CANCEL = 5,
213  INTERNAL_ERROR = 6,
214  FLOW_CONTROL_ERROR = 7,
215  INVALID_ASSOCIATED_STREAM = 8,
216  NUM_STATUS_CODES = 9
217};
218
219// A SPDY stream id is a 31 bit entity.
220typedef uint32 SpdyStreamId;
221
222// A SPDY priority is a number between 0 and 3 (inclusive).
223typedef uint8 SpdyPriority;
224
225// SPDY Priorities. (there are only 2 bits)
226#define SPDY_PRIORITY_LOWEST 3
227#define SPDY_PRIORITY_HIGHEST 0
228
229// -------------------------------------------------------------------------
230// These structures mirror the protocol structure definitions.
231
232// For the control data structures, we pack so that sizes match the
233// protocol over-the-wire sizes.
234#pragma pack(push)
235#pragma pack(1)
236
237// A special structure for the 8 bit flags and 24 bit length fields.
238union FlagsAndLength {
239  uint8 flags_[4];  // 8 bits
240  uint32 length_;   // 24 bits
241};
242
243// The basic SPDY Frame structure.
244struct SpdyFrameBlock {
245  union {
246    struct {
247      uint16 version_;
248      uint16 type_;
249    } control_;
250    struct {
251      SpdyStreamId stream_id_;
252    } data_;
253  };
254  FlagsAndLength flags_length_;
255};
256
257// A SYN_STREAM Control Frame structure.
258struct SpdySynStreamControlFrameBlock : SpdyFrameBlock {
259  SpdyStreamId stream_id_;
260  SpdyStreamId associated_stream_id_;
261  SpdyPriority priority_;
262  uint8 unused_;
263};
264
265// A SYN_REPLY Control Frame structure.
266struct SpdySynReplyControlFrameBlock : SpdyFrameBlock {
267  SpdyStreamId stream_id_;
268  uint16 unused_;
269};
270
271// A RST_STREAM Control Frame structure.
272struct SpdyRstStreamControlFrameBlock : SpdyFrameBlock {
273  SpdyStreamId stream_id_;
274  uint32 status_;
275};
276
277// A SETTINGS Control Frame structure.
278struct SpdySettingsControlFrameBlock : SpdyFrameBlock {
279  uint32 num_entries_;
280  // Variable data here.
281};
282
283// A NOOP Control Frame structure.
284struct SpdyNoopControlFrameBlock : SpdyFrameBlock {
285};
286
287// A PING Control Frame structure.
288struct SpdyPingControlFrameBlock : SpdyFrameBlock {
289  uint32 unique_id_;
290};
291
292// A GOAWAY Control Frame structure.
293struct SpdyGoAwayControlFrameBlock : SpdyFrameBlock {
294  SpdyStreamId last_accepted_stream_id_;
295};
296
297// A HEADERS Control Frame structure.
298struct SpdyHeadersControlFrameBlock : SpdyFrameBlock {
299  SpdyStreamId stream_id_;
300  uint16 unused_;
301};
302
303// A WINDOW_UPDATE Control Frame structure
304struct SpdyWindowUpdateControlFrameBlock : SpdyFrameBlock {
305  SpdyStreamId stream_id_;
306  uint32 delta_window_size_;
307};
308
309// A structure for the 8 bit flags and 24 bit ID fields.
310union SettingsFlagsAndId {
311  // Sets both flags and id to the value for flags-and-id as sent over the wire
312  SettingsFlagsAndId(uint32 val) : id_(val) {}
313  uint8 flags() const { return flags_[0]; }
314  void set_flags(uint8 flags) { flags_[0] = flags; }
315  uint32 id() const { return (ntohl(id_) & kSettingsIdMask); }
316  void set_id(uint32 id) {
317    DCHECK_EQ(0u, (id & ~kSettingsIdMask));
318    id = htonl(id & kSettingsIdMask);
319    id_ = flags() | id;
320  }
321
322  uint8 flags_[4];  // 8 bits
323  uint32 id_;       // 24 bits
324};
325
326#pragma pack(pop)
327
328// -------------------------------------------------------------------------
329// Wrapper classes for various SPDY frames.
330
331// All Spdy Frame types derive from this SpdyFrame class.
332class SpdyFrame {
333 public:
334  // Create a SpdyFrame for a given sized buffer.
335  explicit SpdyFrame(size_t size) : frame_(NULL), owns_buffer_(true) {
336    DCHECK_GE(size, sizeof(struct SpdyFrameBlock));
337    char* buffer = new char[size];
338    memset(buffer, 0, size);
339    frame_ = reinterpret_cast<struct SpdyFrameBlock*>(buffer);
340  }
341
342  // Create a SpdyFrame using a pre-created buffer.
343  // If |owns_buffer| is true, this class takes ownership of the buffer
344  // and will delete it on cleanup.  The buffer must have been created using
345  // new char[].
346  // If |owns_buffer| is false, the caller retains ownership of the buffer and
347  // is responsible for making sure the buffer outlives this frame.  In other
348  // words, this class does NOT create a copy of the buffer.
349  SpdyFrame(char* data, bool owns_buffer)
350      : frame_(reinterpret_cast<struct SpdyFrameBlock*>(data)),
351        owns_buffer_(owns_buffer) {
352    DCHECK(frame_);
353  }
354
355  ~SpdyFrame() {
356    if (owns_buffer_) {
357      char* buffer = reinterpret_cast<char*>(frame_);
358      delete [] buffer;
359    }
360    frame_ = NULL;
361  }
362
363  // Provides access to the frame bytes, which is a buffer containing
364  // the frame packed as expected for sending over the wire.
365  char* data() const { return reinterpret_cast<char*>(frame_); }
366
367  uint8 flags() const { return frame_->flags_length_.flags_[0]; }
368  void set_flags(uint8 flags) { frame_->flags_length_.flags_[0] = flags; }
369
370  uint32 length() const {
371    return ntohl(frame_->flags_length_.length_) & kLengthMask;
372  }
373
374  void set_length(uint32 length) {
375    DCHECK_EQ(0u, (length & ~kLengthMask));
376    length = htonl(length & kLengthMask);
377    frame_->flags_length_.length_ = flags() | length;
378  }
379
380  bool is_control_frame() const {
381    return (ntohs(frame_->control_.version_) & kControlFlagMask) ==
382        kControlFlagMask;
383  }
384
385  // Returns the size of the SpdyFrameBlock structure.
386  // Every SpdyFrame* class has a static size() method for accessing
387  // the size of the data structure which will be sent over the wire.
388  // Note:  this is not the same as sizeof(SpdyFrame).
389  static size_t size() { return sizeof(struct SpdyFrameBlock); }
390
391 protected:
392  SpdyFrameBlock* frame_;
393
394 private:
395  bool owns_buffer_;
396  DISALLOW_COPY_AND_ASSIGN(SpdyFrame);
397};
398
399// A Data Frame.
400class SpdyDataFrame : public SpdyFrame {
401 public:
402  SpdyDataFrame() : SpdyFrame(size()) {}
403  SpdyDataFrame(char* data, bool owns_buffer)
404      : SpdyFrame(data, owns_buffer) {}
405
406  SpdyStreamId stream_id() const {
407    return ntohl(frame_->data_.stream_id_) & kStreamIdMask;
408  }
409
410  // Note that setting the stream id sets the control bit to false.
411  // As stream id should always be set, this means the control bit
412  // should always be set correctly.
413  void set_stream_id(SpdyStreamId id) {
414    DCHECK_EQ(0u, (id & ~kStreamIdMask));
415    frame_->data_.stream_id_ = htonl(id & kStreamIdMask);
416  }
417
418  // Returns the size of the SpdyFrameBlock structure.
419  // Note: this is not the size of the SpdyDataFrame class.
420  static size_t size() { return SpdyFrame::size(); }
421
422  const char* payload() const {
423    return reinterpret_cast<const char*>(frame_) + size();
424  }
425
426 private:
427  DISALLOW_COPY_AND_ASSIGN(SpdyDataFrame);
428};
429
430// A Control Frame.
431class SpdyControlFrame : public SpdyFrame {
432 public:
433  explicit SpdyControlFrame(size_t size) : SpdyFrame(size) {}
434  SpdyControlFrame(char* data, bool owns_buffer)
435      : SpdyFrame(data, owns_buffer) {}
436
437  // Callers can use this method to check if the frame appears to be a valid
438  // frame.  Does not guarantee that there are no errors.
439  bool AppearsToBeAValidControlFrame() const {
440    // Right now we only check if the frame has an out-of-bounds type.
441    uint16 type = ntohs(block()->control_.type_);
442    return (type >= SYN_STREAM && type < NUM_CONTROL_FRAME_TYPES);
443  }
444
445  uint16 version() const {
446    const int kVersionMask = 0x7fff;
447    return ntohs(block()->control_.version_) & kVersionMask;
448  }
449
450  void set_version(uint16 version) {
451    DCHECK_EQ(0u, version & kControlFlagMask);
452    mutable_block()->control_.version_ = htons(kControlFlagMask | version);
453  }
454
455  SpdyControlType type() const {
456    uint16 type = ntohs(block()->control_.type_);
457    DCHECK(type >= SYN_STREAM && type < NUM_CONTROL_FRAME_TYPES);
458    return static_cast<SpdyControlType>(type);
459  }
460
461  void set_type(SpdyControlType type) {
462    DCHECK(type >= SYN_STREAM && type < NUM_CONTROL_FRAME_TYPES);
463    mutable_block()->control_.type_ = htons(type);
464  }
465
466  // Returns true if this control frame is of a type that has a header block,
467  // otherwise it returns false.
468  bool has_header_block() const {
469    return type() == SYN_STREAM || type() == SYN_REPLY || type() == HEADERS;
470  }
471
472  // Returns the size of the SpdyFrameBlock structure.
473  // Note: this is not the size of the SpdyControlFrame class.
474  static size_t size() { return sizeof(SpdyFrameBlock); }
475
476  // The size of the 'Number of Name/Value pairs' field in a Name/Value block.
477  static const size_t kNumNameValuePairsSize = 2;
478
479  // The size of the 'Length of a name' field in a Name/Value block.
480  static const size_t kLengthOfNameSize = 2;
481
482  // The size of the 'Length of a value' field in a Name/Value block.
483  static const size_t kLengthOfValueSize = 2;
484
485 private:
486  const struct SpdyFrameBlock* block() const {
487    return frame_;
488  }
489  struct SpdyFrameBlock* mutable_block() {
490    return frame_;
491  }
492  DISALLOW_COPY_AND_ASSIGN(SpdyControlFrame);
493};
494
495// A SYN_STREAM frame.
496class SpdySynStreamControlFrame : public SpdyControlFrame {
497 public:
498  SpdySynStreamControlFrame() : SpdyControlFrame(size()) {}
499  SpdySynStreamControlFrame(char* data, bool owns_buffer)
500      : SpdyControlFrame(data, owns_buffer) {}
501
502  SpdyStreamId stream_id() const {
503    return ntohl(block()->stream_id_) & kStreamIdMask;
504  }
505
506  void set_stream_id(SpdyStreamId id) {
507    mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
508  }
509
510  SpdyStreamId associated_stream_id() const {
511    return ntohl(block()->associated_stream_id_) & kStreamIdMask;
512  }
513
514  void set_associated_stream_id(SpdyStreamId id) {
515    mutable_block()->associated_stream_id_ = htonl(id & kStreamIdMask);
516  }
517
518  SpdyPriority priority() const {
519    return (block()->priority_ & kPriorityMask) >> 6;
520  }
521
522  // The number of bytes in the header block beyond the frame header length.
523  int header_block_len() const {
524    return length() - (size() - SpdyFrame::size());
525  }
526
527  const char* header_block() const {
528    return reinterpret_cast<const char*>(block()) + size();
529  }
530
531  // Returns the size of the SpdySynStreamControlFrameBlock structure.
532  // Note: this is not the size of the SpdySynStreamControlFrame class.
533  static size_t size() { return sizeof(SpdySynStreamControlFrameBlock); }
534
535 private:
536  const struct SpdySynStreamControlFrameBlock* block() const {
537    return static_cast<SpdySynStreamControlFrameBlock*>(frame_);
538  }
539  struct SpdySynStreamControlFrameBlock* mutable_block() {
540    return static_cast<SpdySynStreamControlFrameBlock*>(frame_);
541  }
542  DISALLOW_COPY_AND_ASSIGN(SpdySynStreamControlFrame);
543};
544
545// A SYN_REPLY frame.
546class SpdySynReplyControlFrame : public SpdyControlFrame {
547 public:
548  SpdySynReplyControlFrame() : SpdyControlFrame(size()) {}
549  SpdySynReplyControlFrame(char* data, bool owns_buffer)
550      : SpdyControlFrame(data, owns_buffer) {}
551
552  SpdyStreamId stream_id() const {
553    return ntohl(block()->stream_id_) & kStreamIdMask;
554  }
555
556  void set_stream_id(SpdyStreamId id) {
557    mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
558  }
559
560  int header_block_len() const {
561    return length() - (size() - SpdyFrame::size());
562  }
563
564  const char* header_block() const {
565    return reinterpret_cast<const char*>(block()) + size();
566  }
567
568  // Returns the size of the SpdySynReplyControlFrameBlock structure.
569  // Note: this is not the size of the SpdySynReplyControlFrame class.
570  static size_t size() { return sizeof(SpdySynReplyControlFrameBlock); }
571
572 private:
573  const struct SpdySynReplyControlFrameBlock* block() const {
574    return static_cast<SpdySynReplyControlFrameBlock*>(frame_);
575  }
576  struct SpdySynReplyControlFrameBlock* mutable_block() {
577    return static_cast<SpdySynReplyControlFrameBlock*>(frame_);
578  }
579  DISALLOW_COPY_AND_ASSIGN(SpdySynReplyControlFrame);
580};
581
582// A RST_STREAM frame.
583class SpdyRstStreamControlFrame : public SpdyControlFrame {
584 public:
585  SpdyRstStreamControlFrame() : SpdyControlFrame(size()) {}
586  SpdyRstStreamControlFrame(char* data, bool owns_buffer)
587      : SpdyControlFrame(data, owns_buffer) {}
588
589  SpdyStreamId stream_id() const {
590    return ntohl(block()->stream_id_) & kStreamIdMask;
591  }
592
593  void set_stream_id(SpdyStreamId id) {
594    mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
595  }
596
597  SpdyStatusCodes status() const {
598    SpdyStatusCodes status =
599        static_cast<SpdyStatusCodes>(ntohl(block()->status_));
600    if (status < INVALID || status >= NUM_STATUS_CODES) {
601      status = INVALID;
602    }
603    return status;
604  }
605  void set_status(SpdyStatusCodes status) {
606    mutable_block()->status_ = htonl(static_cast<uint32>(status));
607  }
608
609  // Returns the size of the SpdyRstStreamControlFrameBlock structure.
610  // Note: this is not the size of the SpdyRstStreamControlFrame class.
611  static size_t size() { return sizeof(SpdyRstStreamControlFrameBlock); }
612
613 private:
614  const struct SpdyRstStreamControlFrameBlock* block() const {
615    return static_cast<SpdyRstStreamControlFrameBlock*>(frame_);
616  }
617  struct SpdyRstStreamControlFrameBlock* mutable_block() {
618    return static_cast<SpdyRstStreamControlFrameBlock*>(frame_);
619  }
620  DISALLOW_COPY_AND_ASSIGN(SpdyRstStreamControlFrame);
621};
622
623class SpdySettingsControlFrame : public SpdyControlFrame {
624 public:
625  SpdySettingsControlFrame() : SpdyControlFrame(size()) {}
626  SpdySettingsControlFrame(char* data, bool owns_buffer)
627      : SpdyControlFrame(data, owns_buffer) {}
628
629  uint32 num_entries() const {
630    return ntohl(block()->num_entries_);
631  }
632
633  void set_num_entries(int val) {
634    mutable_block()->num_entries_ = htonl(val);
635  }
636
637  int header_block_len() const {
638    return length() - (size() - SpdyFrame::size());
639  }
640
641  const char* header_block() const {
642    return reinterpret_cast<const char*>(block()) + size();
643  }
644
645  // Returns the size of the SpdySettingsControlFrameBlock structure.
646  // Note: this is not the size of the SpdySettingsControlFrameBlock class.
647  static size_t size() { return sizeof(SpdySettingsControlFrameBlock); }
648
649 private:
650  const struct SpdySettingsControlFrameBlock* block() const {
651    return static_cast<SpdySettingsControlFrameBlock*>(frame_);
652  }
653  struct SpdySettingsControlFrameBlock* mutable_block() {
654    return static_cast<SpdySettingsControlFrameBlock*>(frame_);
655  }
656  DISALLOW_COPY_AND_ASSIGN(SpdySettingsControlFrame);
657};
658
659class SpdyNoOpControlFrame : public SpdyControlFrame {
660 public:
661  SpdyNoOpControlFrame() : SpdyControlFrame(size()) {}
662  SpdyNoOpControlFrame(char* data, bool owns_buffer)
663      : SpdyControlFrame(data, owns_buffer) {}
664
665  static size_t size() { return sizeof(SpdyNoopControlFrameBlock); }
666};
667
668class SpdyPingControlFrame : public SpdyControlFrame {
669 public:
670  SpdyPingControlFrame() : SpdyControlFrame(size()) {}
671  SpdyPingControlFrame(char* data, bool owns_buffer)
672      : SpdyControlFrame(data, owns_buffer) {}
673
674  uint32 unique_id() const {
675    return ntohl(block()->unique_id_);
676  }
677
678  void set_unique_id(uint32 unique_id) {
679    mutable_block()->unique_id_ = htonl(unique_id);
680  }
681
682  static size_t size() { return sizeof(SpdyPingControlFrameBlock); }
683
684 private:
685  const struct SpdyPingControlFrameBlock* block() const {
686    return static_cast<SpdyPingControlFrameBlock*>(frame_);
687  }
688  struct SpdyPingControlFrameBlock* mutable_block() {
689    return static_cast<SpdyPingControlFrameBlock*>(frame_);
690  }
691};
692
693class SpdyGoAwayControlFrame : public SpdyControlFrame {
694 public:
695  SpdyGoAwayControlFrame() : SpdyControlFrame(size()) {}
696  SpdyGoAwayControlFrame(char* data, bool owns_buffer)
697      : SpdyControlFrame(data, owns_buffer) {}
698
699  SpdyStreamId last_accepted_stream_id() const {
700    return ntohl(block()->last_accepted_stream_id_) & kStreamIdMask;
701  }
702
703  void set_last_accepted_stream_id(SpdyStreamId id) {
704    mutable_block()->last_accepted_stream_id_ = htonl(id & kStreamIdMask);
705  }
706
707  static size_t size() { return sizeof(SpdyGoAwayControlFrameBlock); }
708
709 private:
710  const struct SpdyGoAwayControlFrameBlock* block() const {
711    return static_cast<SpdyGoAwayControlFrameBlock*>(frame_);
712  }
713  struct SpdyGoAwayControlFrameBlock* mutable_block() {
714    return static_cast<SpdyGoAwayControlFrameBlock*>(frame_);
715  }
716  DISALLOW_COPY_AND_ASSIGN(SpdyGoAwayControlFrame);
717};
718
719// A HEADERS frame.
720class SpdyHeadersControlFrame : public SpdyControlFrame {
721 public:
722  SpdyHeadersControlFrame() : SpdyControlFrame(size()) {}
723  SpdyHeadersControlFrame(char* data, bool owns_buffer)
724      : SpdyControlFrame(data, owns_buffer) {}
725
726  SpdyStreamId stream_id() const {
727    return ntohl(block()->stream_id_) & kStreamIdMask;
728  }
729
730  void set_stream_id(SpdyStreamId id) {
731    mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
732  }
733
734  // The number of bytes in the header block beyond the frame header length.
735  int header_block_len() const {
736    return length() - (size() - SpdyFrame::size());
737  }
738
739  const char* header_block() const {
740    return reinterpret_cast<const char*>(block()) + size();
741  }
742
743  // Returns the size of the SpdyHeadersControlFrameBlock structure.
744  // Note: this is not the size of the SpdyHeadersControlFrame class.
745  static size_t size() { return sizeof(SpdyHeadersControlFrameBlock); }
746
747 private:
748  const struct SpdyHeadersControlFrameBlock* block() const {
749    return static_cast<SpdyHeadersControlFrameBlock*>(frame_);
750  }
751  struct SpdyHeadersControlFrameBlock* mutable_block() {
752    return static_cast<SpdyHeadersControlFrameBlock*>(frame_);
753  }
754  DISALLOW_COPY_AND_ASSIGN(SpdyHeadersControlFrame);
755};
756
757// A WINDOW_UPDATE frame.
758class SpdyWindowUpdateControlFrame : public SpdyControlFrame {
759 public:
760  SpdyWindowUpdateControlFrame() : SpdyControlFrame(size()) {}
761  SpdyWindowUpdateControlFrame(char* data, bool owns_buffer)
762      : SpdyControlFrame(data, owns_buffer) {}
763
764  SpdyStreamId stream_id() const {
765    return ntohl(block()->stream_id_) & kStreamIdMask;
766  }
767
768  void set_stream_id(SpdyStreamId id) {
769    mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
770  }
771
772  uint32 delta_window_size() const {
773    return ntohl(block()->delta_window_size_);
774  }
775
776  void set_delta_window_size(uint32 delta_window_size) {
777    mutable_block()->delta_window_size_ = htonl(delta_window_size);
778  }
779
780  // Returns the size of the SpdyWindowUpdateControlFrameBlock structure.
781  // Note: this is not the size of the SpdyWindowUpdateControlFrame class.
782  static size_t size() { return sizeof(SpdyWindowUpdateControlFrameBlock); }
783
784 private:
785  const struct SpdyWindowUpdateControlFrameBlock* block() const {
786    return static_cast<SpdyWindowUpdateControlFrameBlock*>(frame_);
787  }
788  struct SpdyWindowUpdateControlFrameBlock* mutable_block() {
789    return static_cast<SpdyWindowUpdateControlFrameBlock*>(frame_);
790  }
791
792  DISALLOW_COPY_AND_ASSIGN(SpdyWindowUpdateControlFrame);
793};
794
795}  // namespace spdy
796
797#endif  // NET_SPDY_SPDY_PROTOCOL_H_
798