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   SETTINGS_ROUND_TRIP_TIME = 0x3,
    195   SETTINGS_MAX_CONCURRENT_STREAMS = 0x4,
    196   SETTINGS_CURRENT_CWND = 0x5,
    197   // Downstream byte retransmission rate in percentage.
    198   SETTINGS_DOWNLOAD_RETRANS_RATE = 0x6,
    199   // Initial window size in bytes
    200   SETTINGS_INITIAL_WINDOW_SIZE = 0x7
    201 };
    202 
    203 // Status codes, as used in control frames (primarily RST_STREAM).
    204 enum SpdyStatusCodes {
    205   INVALID = 0,
    206   PROTOCOL_ERROR = 1,
    207   INVALID_STREAM = 2,
    208   REFUSED_STREAM = 3,
    209   UNSUPPORTED_VERSION = 4,
    210   CANCEL = 5,
    211   INTERNAL_ERROR = 6,
    212   FLOW_CONTROL_ERROR = 7,
    213   INVALID_ASSOCIATED_STREAM = 8,
    214   NUM_STATUS_CODES = 9
    215 };
    216 
    217 // A SPDY stream id is a 31 bit entity.
    218 typedef uint32 SpdyStreamId;
    219 
    220 // A SPDY priority is a number between 0 and 3 (inclusive).
    221 typedef uint8 SpdyPriority;
    222 
    223 // SPDY Priorities. (there are only 2 bits)
    224 #define SPDY_PRIORITY_LOWEST 3
    225 #define SPDY_PRIORITY_HIGHEST 0
    226 
    227 // -------------------------------------------------------------------------
    228 // These structures mirror the protocol structure definitions.
    229 
    230 // For the control data structures, we pack so that sizes match the
    231 // protocol over-the-wire sizes.
    232 #pragma pack(push)
    233 #pragma pack(1)
    234 
    235 // A special structure for the 8 bit flags and 24 bit length fields.
    236 union FlagsAndLength {
    237   uint8 flags_[4];  // 8 bits
    238   uint32 length_;   // 24 bits
    239 };
    240 
    241 // The basic SPDY Frame structure.
    242 struct SpdyFrameBlock {
    243   union {
    244     struct {
    245       uint16 version_;
    246       uint16 type_;
    247     } control_;
    248     struct {
    249       SpdyStreamId stream_id_;
    250     } data_;
    251   };
    252   FlagsAndLength flags_length_;
    253 };
    254 
    255 // A SYN_STREAM Control Frame structure.
    256 struct SpdySynStreamControlFrameBlock : SpdyFrameBlock {
    257   SpdyStreamId stream_id_;
    258   SpdyStreamId associated_stream_id_;
    259   SpdyPriority priority_;
    260   uint8 unused_;
    261 };
    262 
    263 // A SYN_REPLY Control Frame structure.
    264 struct SpdySynReplyControlFrameBlock : SpdyFrameBlock {
    265   SpdyStreamId stream_id_;
    266   uint16 unused_;
    267 };
    268 
    269 // A RST_STREAM Control Frame structure.
    270 struct SpdyRstStreamControlFrameBlock : SpdyFrameBlock {
    271   SpdyStreamId stream_id_;
    272   uint32 status_;
    273 };
    274 
    275 // A SETTINGS Control Frame structure.
    276 struct SpdySettingsControlFrameBlock : SpdyFrameBlock {
    277   uint32 num_entries_;
    278   // Variable data here.
    279 };
    280 
    281 // A GOAWAY Control Frame structure.
    282 struct SpdyGoAwayControlFrameBlock : SpdyFrameBlock {
    283   SpdyStreamId last_accepted_stream_id_;
    284 };
    285 
    286 // A HEADERS Control Frame structure.
    287 struct SpdyHeadersControlFrameBlock : SpdyFrameBlock {
    288   SpdyStreamId stream_id_;
    289   uint16 unused_;
    290 };
    291 
    292 // A WINDOW_UPDATE Control Frame structure
    293 struct SpdyWindowUpdateControlFrameBlock : SpdyFrameBlock {
    294   SpdyStreamId stream_id_;
    295   uint32 delta_window_size_;
    296 };
    297 
    298 // A structure for the 8 bit flags and 24 bit ID fields.
    299 union SettingsFlagsAndId {
    300   SettingsFlagsAndId(uint32 val) : id_(val) {}
    301   uint8 flags() const { return flags_[0]; }
    302   void set_flags(uint8 flags) { flags_[0] = flags; }
    303   uint32 id() const { return (ntohl(id_) & kSettingsIdMask); }
    304   void set_id(uint32 id) {
    305     DCHECK_EQ(0u, (id & ~kSettingsIdMask));
    306     id = htonl(id & kSettingsIdMask);
    307     id_ = flags() | id;
    308   }
    309 
    310   uint8 flags_[4];  // 8 bits
    311   uint32 id_;       // 24 bits
    312 };
    313 
    314 #pragma pack(pop)
    315 
    316 // -------------------------------------------------------------------------
    317 // Wrapper classes for various SPDY frames.
    318 
    319 // All Spdy Frame types derive from this SpdyFrame class.
    320 class SpdyFrame {
    321  public:
    322   // Create a SpdyFrame for a given sized buffer.
    323   explicit SpdyFrame(size_t size) : frame_(NULL), owns_buffer_(true) {
    324     DCHECK_GE(size, sizeof(struct SpdyFrameBlock));
    325     char* buffer = new char[size];
    326     memset(buffer, 0, size);
    327     frame_ = reinterpret_cast<struct SpdyFrameBlock*>(buffer);
    328   }
    329 
    330   // Create a SpdyFrame using a pre-created buffer.
    331   // If |owns_buffer| is true, this class takes ownership of the buffer
    332   // and will delete it on cleanup.  The buffer must have been created using
    333   // new char[].
    334   // If |owns_buffer| is false, the caller retains ownership of the buffer and
    335   // is responsible for making sure the buffer outlives this frame.  In other
    336   // words, this class does NOT create a copy of the buffer.
    337   SpdyFrame(char* data, bool owns_buffer)
    338       : frame_(reinterpret_cast<struct SpdyFrameBlock*>(data)),
    339         owns_buffer_(owns_buffer) {
    340     DCHECK(frame_);
    341   }
    342 
    343   ~SpdyFrame() {
    344     if (owns_buffer_) {
    345       char* buffer = reinterpret_cast<char*>(frame_);
    346       delete [] buffer;
    347     }
    348     frame_ = NULL;
    349   }
    350 
    351   // Provides access to the frame bytes, which is a buffer containing
    352   // the frame packed as expected for sending over the wire.
    353   char* data() const { return reinterpret_cast<char*>(frame_); }
    354 
    355   uint8 flags() const { return frame_->flags_length_.flags_[0]; }
    356   void set_flags(uint8 flags) { frame_->flags_length_.flags_[0] = flags; }
    357 
    358   uint32 length() const {
    359     return ntohl(frame_->flags_length_.length_) & kLengthMask;
    360   }
    361 
    362   void set_length(uint32 length) {
    363     DCHECK_EQ(0u, (length & ~kLengthMask));
    364     length = htonl(length & kLengthMask);
    365     frame_->flags_length_.length_ = flags() | length;
    366   }
    367 
    368   bool is_control_frame() const {
    369     return (ntohs(frame_->control_.version_) & kControlFlagMask) ==
    370         kControlFlagMask;
    371   }
    372 
    373   // Returns the size of the SpdyFrameBlock structure.
    374   // Every SpdyFrame* class has a static size() method for accessing
    375   // the size of the data structure which will be sent over the wire.
    376   // Note:  this is not the same as sizeof(SpdyFrame).
    377   static size_t size() { return sizeof(struct SpdyFrameBlock); }
    378 
    379  protected:
    380   SpdyFrameBlock* frame_;
    381 
    382  private:
    383   bool owns_buffer_;
    384   DISALLOW_COPY_AND_ASSIGN(SpdyFrame);
    385 };
    386 
    387 // A Data Frame.
    388 class SpdyDataFrame : public SpdyFrame {
    389  public:
    390   SpdyDataFrame() : SpdyFrame(size()) {}
    391   SpdyDataFrame(char* data, bool owns_buffer)
    392       : SpdyFrame(data, owns_buffer) {}
    393 
    394   SpdyStreamId stream_id() const {
    395     return ntohl(frame_->data_.stream_id_) & kStreamIdMask;
    396   }
    397 
    398   // Note that setting the stream id sets the control bit to false.
    399   // As stream id should always be set, this means the control bit
    400   // should always be set correctly.
    401   void set_stream_id(SpdyStreamId id) {
    402     DCHECK_EQ(0u, (id & ~kStreamIdMask));
    403     frame_->data_.stream_id_ = htonl(id & kStreamIdMask);
    404   }
    405 
    406   // Returns the size of the SpdyFrameBlock structure.
    407   // Note: this is not the size of the SpdyDataFrame class.
    408   static size_t size() { return SpdyFrame::size(); }
    409 
    410   const char* payload() const {
    411     return reinterpret_cast<const char*>(frame_) + size();
    412   }
    413 
    414  private:
    415   DISALLOW_COPY_AND_ASSIGN(SpdyDataFrame);
    416 };
    417 
    418 // A Control Frame.
    419 class SpdyControlFrame : public SpdyFrame {
    420  public:
    421   explicit SpdyControlFrame(size_t size) : SpdyFrame(size) {}
    422   SpdyControlFrame(char* data, bool owns_buffer)
    423       : SpdyFrame(data, owns_buffer) {}
    424 
    425   // Callers can use this method to check if the frame appears to be a valid
    426   // frame.  Does not guarantee that there are no errors.
    427   bool AppearsToBeAValidControlFrame() const {
    428     // Right now we only check if the frame has an out-of-bounds type.
    429     uint16 type = ntohs(block()->control_.type_);
    430     return (type >= SYN_STREAM && type < NUM_CONTROL_FRAME_TYPES);
    431   }
    432 
    433   uint16 version() const {
    434     const int kVersionMask = 0x7fff;
    435     return ntohs(block()->control_.version_) & kVersionMask;
    436   }
    437 
    438   void set_version(uint16 version) {
    439     DCHECK_EQ(0u, version & kControlFlagMask);
    440     mutable_block()->control_.version_ = htons(kControlFlagMask | version);
    441   }
    442 
    443   SpdyControlType type() const {
    444     uint16 type = ntohs(block()->control_.type_);
    445     DCHECK(type >= SYN_STREAM && type < NUM_CONTROL_FRAME_TYPES);
    446     return static_cast<SpdyControlType>(type);
    447   }
    448 
    449   void set_type(SpdyControlType type) {
    450     DCHECK(type >= SYN_STREAM && type < NUM_CONTROL_FRAME_TYPES);
    451     mutable_block()->control_.type_ = htons(type);
    452   }
    453 
    454   // Returns the size of the SpdyFrameBlock structure.
    455   // Note: this is not the size of the SpdyControlFrame class.
    456   static size_t size() { return sizeof(SpdyFrameBlock); }
    457 
    458  private:
    459   const struct SpdyFrameBlock* block() const {
    460     return frame_;
    461   }
    462   struct SpdyFrameBlock* mutable_block() {
    463     return frame_;
    464   }
    465   DISALLOW_COPY_AND_ASSIGN(SpdyControlFrame);
    466 };
    467 
    468 // A SYN_STREAM frame.
    469 class SpdySynStreamControlFrame : public SpdyControlFrame {
    470  public:
    471   SpdySynStreamControlFrame() : SpdyControlFrame(size()) {}
    472   SpdySynStreamControlFrame(char* data, bool owns_buffer)
    473       : SpdyControlFrame(data, owns_buffer) {}
    474 
    475   SpdyStreamId stream_id() const {
    476     return ntohl(block()->stream_id_) & kStreamIdMask;
    477   }
    478 
    479   void set_stream_id(SpdyStreamId id) {
    480     mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
    481   }
    482 
    483   SpdyStreamId associated_stream_id() const {
    484     return ntohl(block()->associated_stream_id_) & kStreamIdMask;
    485   }
    486 
    487   void set_associated_stream_id(SpdyStreamId id) {
    488     mutable_block()->associated_stream_id_ = htonl(id & kStreamIdMask);
    489   }
    490 
    491   SpdyPriority priority() const {
    492     return (block()->priority_ & kPriorityMask) >> 6;
    493   }
    494 
    495   // The number of bytes in the header block beyond the frame header length.
    496   int header_block_len() const {
    497     return length() - (size() - SpdyFrame::size());
    498   }
    499 
    500   const char* header_block() const {
    501     return reinterpret_cast<const char*>(block()) + size();
    502   }
    503 
    504   // Returns the size of the SpdySynStreamControlFrameBlock structure.
    505   // Note: this is not the size of the SpdySynStreamControlFrame class.
    506   static size_t size() { return sizeof(SpdySynStreamControlFrameBlock); }
    507 
    508  private:
    509   const struct SpdySynStreamControlFrameBlock* block() const {
    510     return static_cast<SpdySynStreamControlFrameBlock*>(frame_);
    511   }
    512   struct SpdySynStreamControlFrameBlock* mutable_block() {
    513     return static_cast<SpdySynStreamControlFrameBlock*>(frame_);
    514   }
    515   DISALLOW_COPY_AND_ASSIGN(SpdySynStreamControlFrame);
    516 };
    517 
    518 // A SYN_REPLY frame.
    519 class SpdySynReplyControlFrame : public SpdyControlFrame {
    520  public:
    521   SpdySynReplyControlFrame() : SpdyControlFrame(size()) {}
    522   SpdySynReplyControlFrame(char* data, bool owns_buffer)
    523       : SpdyControlFrame(data, owns_buffer) {}
    524 
    525   SpdyStreamId stream_id() const {
    526     return ntohl(block()->stream_id_) & kStreamIdMask;
    527   }
    528 
    529   void set_stream_id(SpdyStreamId id) {
    530     mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
    531   }
    532 
    533   int header_block_len() const {
    534     return length() - (size() - SpdyFrame::size());
    535   }
    536 
    537   const char* header_block() const {
    538     return reinterpret_cast<const char*>(block()) + size();
    539   }
    540 
    541   // Returns the size of the SpdySynReplyControlFrameBlock structure.
    542   // Note: this is not the size of the SpdySynReplyControlFrame class.
    543   static size_t size() { return sizeof(SpdySynReplyControlFrameBlock); }
    544 
    545  private:
    546   const struct SpdySynReplyControlFrameBlock* block() const {
    547     return static_cast<SpdySynReplyControlFrameBlock*>(frame_);
    548   }
    549   struct SpdySynReplyControlFrameBlock* mutable_block() {
    550     return static_cast<SpdySynReplyControlFrameBlock*>(frame_);
    551   }
    552   DISALLOW_COPY_AND_ASSIGN(SpdySynReplyControlFrame);
    553 };
    554 
    555 // A RST_STREAM frame.
    556 class SpdyRstStreamControlFrame : public SpdyControlFrame {
    557  public:
    558   SpdyRstStreamControlFrame() : SpdyControlFrame(size()) {}
    559   SpdyRstStreamControlFrame(char* data, bool owns_buffer)
    560       : SpdyControlFrame(data, owns_buffer) {}
    561 
    562   SpdyStreamId stream_id() const {
    563     return ntohl(block()->stream_id_) & kStreamIdMask;
    564   }
    565 
    566   void set_stream_id(SpdyStreamId id) {
    567     mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
    568   }
    569 
    570   SpdyStatusCodes status() const {
    571     return static_cast<SpdyStatusCodes>(ntohl(block()->status_));
    572   }
    573   void set_status(SpdyStatusCodes status) {
    574     mutable_block()->status_ = htonl(static_cast<uint32>(status));
    575   }
    576 
    577   // Returns the size of the SpdyRstStreamControlFrameBlock structure.
    578   // Note: this is not the size of the SpdyRstStreamControlFrame class.
    579   static size_t size() { return sizeof(SpdyRstStreamControlFrameBlock); }
    580 
    581  private:
    582   const struct SpdyRstStreamControlFrameBlock* block() const {
    583     return static_cast<SpdyRstStreamControlFrameBlock*>(frame_);
    584   }
    585   struct SpdyRstStreamControlFrameBlock* mutable_block() {
    586     return static_cast<SpdyRstStreamControlFrameBlock*>(frame_);
    587   }
    588   DISALLOW_COPY_AND_ASSIGN(SpdyRstStreamControlFrame);
    589 };
    590 
    591 class SpdySettingsControlFrame : public SpdyControlFrame {
    592  public:
    593   SpdySettingsControlFrame() : SpdyControlFrame(size()) {}
    594   SpdySettingsControlFrame(char* data, bool owns_buffer)
    595       : SpdyControlFrame(data, owns_buffer) {}
    596 
    597   uint32 num_entries() const {
    598     return ntohl(block()->num_entries_);
    599   }
    600 
    601   void set_num_entries(int val) {
    602     mutable_block()->num_entries_ = htonl(val);
    603   }
    604 
    605   int header_block_len() const {
    606     return length() - (size() - SpdyFrame::size());
    607   }
    608 
    609   const char* header_block() const {
    610     return reinterpret_cast<const char*>(block()) + size();
    611   }
    612 
    613   // Returns the size of the SpdySettingsControlFrameBlock structure.
    614   // Note: this is not the size of the SpdySettingsControlFrameBlock class.
    615   static size_t size() { return sizeof(SpdySettingsControlFrameBlock); }
    616 
    617  private:
    618   const struct SpdySettingsControlFrameBlock* block() const {
    619     return static_cast<SpdySettingsControlFrameBlock*>(frame_);
    620   }
    621   struct SpdySettingsControlFrameBlock* mutable_block() {
    622     return static_cast<SpdySettingsControlFrameBlock*>(frame_);
    623   }
    624   DISALLOW_COPY_AND_ASSIGN(SpdySettingsControlFrame);
    625 };
    626 
    627 class SpdyGoAwayControlFrame : public SpdyControlFrame {
    628  public:
    629   SpdyGoAwayControlFrame() : SpdyControlFrame(size()) {}
    630   SpdyGoAwayControlFrame(char* data, bool owns_buffer)
    631       : SpdyControlFrame(data, owns_buffer) {}
    632 
    633   SpdyStreamId last_accepted_stream_id() const {
    634     return ntohl(block()->last_accepted_stream_id_) & kStreamIdMask;
    635   }
    636 
    637   void set_last_accepted_stream_id(SpdyStreamId id) {
    638     mutable_block()->last_accepted_stream_id_ = htonl(id & kStreamIdMask);
    639   }
    640 
    641   static size_t size() { return sizeof(SpdyGoAwayControlFrameBlock); }
    642 
    643  private:
    644   const struct SpdyGoAwayControlFrameBlock* block() const {
    645     return static_cast<SpdyGoAwayControlFrameBlock*>(frame_);
    646   }
    647   struct SpdyGoAwayControlFrameBlock* mutable_block() {
    648     return static_cast<SpdyGoAwayControlFrameBlock*>(frame_);
    649   }
    650   DISALLOW_COPY_AND_ASSIGN(SpdyGoAwayControlFrame);
    651 };
    652 
    653 // A HEADERS frame.
    654 class SpdyHeadersControlFrame : public SpdyControlFrame {
    655  public:
    656   SpdyHeadersControlFrame() : SpdyControlFrame(size()) {}
    657   SpdyHeadersControlFrame(char* data, bool owns_buffer)
    658       : SpdyControlFrame(data, owns_buffer) {}
    659 
    660   SpdyStreamId stream_id() const {
    661     return ntohl(block()->stream_id_) & kStreamIdMask;
    662   }
    663 
    664   void set_stream_id(SpdyStreamId id) {
    665     mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
    666   }
    667 
    668   // The number of bytes in the header block beyond the frame header length.
    669   int header_block_len() const {
    670     return length() - (size() - SpdyFrame::size());
    671   }
    672 
    673   const char* header_block() const {
    674     return reinterpret_cast<const char*>(block()) + size();
    675   }
    676 
    677   // Returns the size of the SpdyHeadersControlFrameBlock structure.
    678   // Note: this is not the size of the SpdyHeadersControlFrame class.
    679   static size_t size() { return sizeof(SpdyHeadersControlFrameBlock); }
    680 
    681  private:
    682   const struct SpdyHeadersControlFrameBlock* block() const {
    683     return static_cast<SpdyHeadersControlFrameBlock*>(frame_);
    684   }
    685   struct SpdyHeadersControlFrameBlock* mutable_block() {
    686     return static_cast<SpdyHeadersControlFrameBlock*>(frame_);
    687   }
    688   DISALLOW_COPY_AND_ASSIGN(SpdyHeadersControlFrame);
    689 };
    690 
    691 // A WINDOW_UPDATE frame.
    692 class SpdyWindowUpdateControlFrame : public SpdyControlFrame {
    693  public:
    694   SpdyWindowUpdateControlFrame() : SpdyControlFrame(size()) {}
    695   SpdyWindowUpdateControlFrame(char* data, bool owns_buffer)
    696       : SpdyControlFrame(data, owns_buffer) {}
    697 
    698   SpdyStreamId stream_id() const {
    699     return ntohl(block()->stream_id_) & kStreamIdMask;
    700   }
    701 
    702   void set_stream_id(SpdyStreamId id) {
    703     mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
    704   }
    705 
    706   uint32 delta_window_size() const {
    707     return ntohl(block()->delta_window_size_);
    708   }
    709 
    710   void set_delta_window_size(uint32 delta_window_size) {
    711     mutable_block()->delta_window_size_ = htonl(delta_window_size);
    712   }
    713 
    714   // Returns the size of the SpdyWindowUpdateControlFrameBlock structure.
    715   // Note: this is not the size of the SpdyWindowUpdateControlFrame class.
    716   static size_t size() { return sizeof(SpdyWindowUpdateControlFrameBlock); }
    717 
    718  private:
    719   const struct SpdyWindowUpdateControlFrameBlock* block() const {
    720     return static_cast<SpdyWindowUpdateControlFrameBlock*>(frame_);
    721   }
    722   struct SpdyWindowUpdateControlFrameBlock* mutable_block() {
    723     return static_cast<SpdyWindowUpdateControlFrameBlock*>(frame_);
    724   }
    725 
    726   DISALLOW_COPY_AND_ASSIGN(SpdyWindowUpdateControlFrame);
    727 };
    728 
    729 }  // namespace spdy
    730 
    731 #endif  // NET_SPDY_SPDY_PROTOCOL_H_
    732