Home | History | Annotate | Download | only in spdy
      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 //  +----------------------------------+
    126 namespace spdy {
    127 
    128 // This implementation of Spdy is version 2; It's like version 1, with some
    129 // minor tweaks.
    130 const int kSpdyProtocolVersion = 2;
    131 
    132 // Initial window size for a Spdy stream
    133 const size_t kSpdyStreamInitialWindowSize = 64 * 1024;  // 64 KBytes
    134 
    135 // Maximum window size for a Spdy stream
    136 const size_t kSpdyStreamMaximumWindowSize = std::numeric_limits<int32>::max();
    137 
    138 // HTTP-over-SPDY header constants
    139 const char kMethod[] = "method";
    140 const char kStatus[] = "status";
    141 const char kUrl[] = "url";
    142 const 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.
    145 const 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.
    152 enum 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.
    166 enum SpdyDataFlags {
    167   DATA_FLAG_NONE = 0,
    168   DATA_FLAG_FIN = 1,
    169   DATA_FLAG_COMPRESSED = 2
    170 };
    171 
    172 // Flags on control packets
    173 enum 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.
    180 enum SpdySettingsControlFlags {
    181   SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS = 0x1
    182 };
    183 
    184 // Flags for settings within a SETTINGS frame.
    185 enum SpdySettingsFlags {
    186   SETTINGS_FLAG_PLEASE_PERSIST = 0x1,
    187   SETTINGS_FLAG_PERSISTED = 0x2
    188 };
    189 
    190 // List of known settings.
    191 enum 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).
    206 enum 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.
    220 typedef uint32 SpdyStreamId;
    221 
    222 // A SPDY priority is a number between 0 and 3 (inclusive).
    223 typedef 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.
    238 union FlagsAndLength {
    239   uint8 flags_[4];  // 8 bits
    240   uint32 length_;   // 24 bits
    241 };
    242 
    243 // The basic SPDY Frame structure.
    244 struct 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.
    258 struct 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.
    266 struct SpdySynReplyControlFrameBlock : SpdyFrameBlock {
    267   SpdyStreamId stream_id_;
    268   uint16 unused_;
    269 };
    270 
    271 // A RST_STREAM Control Frame structure.
    272 struct SpdyRstStreamControlFrameBlock : SpdyFrameBlock {
    273   SpdyStreamId stream_id_;
    274   uint32 status_;
    275 };
    276 
    277 // A SETTINGS Control Frame structure.
    278 struct SpdySettingsControlFrameBlock : SpdyFrameBlock {
    279   uint32 num_entries_;
    280   // Variable data here.
    281 };
    282 
    283 // A NOOP Control Frame structure.
    284 struct SpdyNoopControlFrameBlock : SpdyFrameBlock {
    285 };
    286 
    287 // A PING Control Frame structure.
    288 struct SpdyPingControlFrameBlock : SpdyFrameBlock {
    289   uint32 unique_id_;
    290 };
    291 
    292 // A GOAWAY Control Frame structure.
    293 struct SpdyGoAwayControlFrameBlock : SpdyFrameBlock {
    294   SpdyStreamId last_accepted_stream_id_;
    295 };
    296 
    297 // A HEADERS Control Frame structure.
    298 struct SpdyHeadersControlFrameBlock : SpdyFrameBlock {
    299   SpdyStreamId stream_id_;
    300   uint16 unused_;
    301 };
    302 
    303 // A WINDOW_UPDATE Control Frame structure
    304 struct 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.
    310 union 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.
    332 class 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.
    400 class 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.
    431 class 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.
    496 class 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.
    546 class 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.
    583 class 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 
    623 class 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 
    659 class 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 
    668 class 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 
    693 class 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.
    720 class 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.
    758 class 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