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