spdy_protocol.h revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This file contains some protocol structures for use with Spdy.
6
7#ifndef NET_SPDY_SPDY_PROTOCOL_H_
8#define NET_SPDY_SPDY_PROTOCOL_H_
9
10#include <limits>
11
12#include "base/basictypes.h"
13#include "base/logging.h"
14#include "base/sys_byteorder.h"
15#include "net/spdy/spdy_bitmasks.h"
16
17//  Data Frame Format
18//  +----------------------------------+
19//  |0|       Stream-ID (31bits)       |
20//  +----------------------------------+
21//  | flags (8)  |  Length (24 bits)   |
22//  +----------------------------------+
23//  |               Data               |
24//  +----------------------------------+
25//
26//  Control Frame Format
27//  +----------------------------------+
28//  |1| Version(15bits) | Type(16bits) |
29//  +----------------------------------+
30//  | flags (8)  |  Length (24 bits)   |
31//  +----------------------------------+
32//  |               Data               |
33//  +----------------------------------+
34//
35//  Control Frame: SYN_STREAM
36//  +----------------------------------+
37//  |1|000000000000001|0000000000000001|
38//  +----------------------------------+
39//  | flags (8)  |  Length (24 bits)   |  >= 12
40//  +----------------------------------+
41//  |X|       Stream-ID(31bits)        |
42//  +----------------------------------+
43//  |X|Associated-To-Stream-ID (31bits)|
44//  +----------------------------------+
45//  |Pri| unused      | Length (16bits)|
46//  +----------------------------------+
47//
48//  Control Frame: SYN_REPLY
49//  +----------------------------------+
50//  |1|000000000000001|0000000000000010|
51//  +----------------------------------+
52//  | flags (8)  |  Length (24 bits)   |  >= 8
53//  +----------------------------------+
54//  |X|       Stream-ID(31bits)        |
55//  +----------------------------------+
56//  | unused (16 bits)| Length (16bits)|
57//  +----------------------------------+
58//
59//  Control Frame: RST_STREAM
60//  +----------------------------------+
61//  |1|000000000000001|0000000000000011|
62//  +----------------------------------+
63//  | flags (8)  |  Length (24 bits)   |  >= 4
64//  +----------------------------------+
65//  |X|       Stream-ID(31bits)        |
66//  +----------------------------------+
67//  |        Status code (32 bits)     |
68//  +----------------------------------+
69//
70//  Control Frame: SETTINGS
71//  +----------------------------------+
72//  |1|000000000000001|0000000000000100|
73//  +----------------------------------+
74//  | flags (8)  |  Length (24 bits)   |
75//  +----------------------------------+
76//  |        # of entries (32)         |
77//  +----------------------------------+
78//
79//  Control Frame: NOOP
80//  +----------------------------------+
81//  |1|000000000000001|0000000000000101|
82//  +----------------------------------+
83//  | flags (8)  |  Length (24 bits)   | = 0
84//  +----------------------------------+
85//
86//  Control Frame: PING
87//  +----------------------------------+
88//  |1|000000000000001|0000000000000110|
89//  +----------------------------------+
90//  | flags (8)  |  Length (24 bits)   | = 4
91//  +----------------------------------+
92//  |        Unique id (32 bits)       |
93//  +----------------------------------+
94//
95//  Control Frame: GOAWAY
96//  +----------------------------------+
97//  |1|000000000000001|0000000000000111|
98//  +----------------------------------+
99//  | flags (8)  |  Length (24 bits)   | = 4
100//  +----------------------------------+
101//  |X|  Last-accepted-stream-id       |
102//  +----------------------------------+
103//
104//  Control Frame: HEADERS
105//  +----------------------------------+
106//  |1|000000000000001|0000000000001000|
107//  +----------------------------------+
108//  | flags (8)  |  Length (24 bits)   | >= 8
109//  +----------------------------------+
110//  |X|      Stream-ID (31 bits)       |
111//  +----------------------------------+
112//  | unused (16 bits)| Length (16bits)|
113//  +----------------------------------+
114//
115//  Control Frame: WINDOW_UPDATE
116//  +----------------------------------+
117//  |1|000000000000001|0000000000001001|
118//  +----------------------------------+
119//  | flags (8)  |  Length (24 bits)   | = 8
120//  +----------------------------------+
121//  |X|      Stream-ID (31 bits)       |
122//  +----------------------------------+
123//  |   Delta-Window-Size (32 bits)    |
124//  +----------------------------------+
125//
126//  Control Frame: CREDENTIAL
127//  +----------------------------------+
128//  |1|000000000000001|0000000000001010|
129//  +----------------------------------+
130//  | flags (8)  |  Length (24 bits)   | >= 12
131//  +----------------------------------+
132//  |  Slot (16 bits) |                |
133//  +-----------------+                |
134//  |      Proof Length (32 bits)      |
135//  +----------------------------------+
136//  |               Proof              |
137//  +----------------------------------+ <+
138//  |   Certificate Length (32 bits)   |  |
139//  +----------------------------------+  | Repeated until end of frame
140//  |            Certificate           |  |
141//  +----------------------------------+ <+
142//
143
144namespace net {
145
146// Initial window size for a Spdy stream
147const int32 kSpdyStreamInitialWindowSize = 64 * 1024;  // 64 KBytes
148
149// Maximum window size for a Spdy stream
150const int32 kSpdyStreamMaximumWindowSize = 0x7FFFFFFF;  // Max signed 32bit int
151
152// SPDY 2 dictionary.
153// This is just a hacked dictionary to use for shrinking HTTP-like headers.
154const char kV2Dictionary[] =
155  "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
156  "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
157  "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
158  "-agent10010120020120220320420520630030130230330430530630740040140240340440"
159  "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
160  "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
161  "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
162  "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
163  "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
164  "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
165  "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
166  "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
167  ".1statusversionurl";
168const int kV2DictionarySize = arraysize(kV2Dictionary);
169
170// SPDY 3 dictionary.
171const char kV3Dictionary[] = {
172  0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69,  // ....opti
173  0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68,  // ons....h
174  0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70,  // ead....p
175  0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70,  // ost....p
176  0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65,  // ut....de
177  0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05,  // lete....
178  0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00,  // trace...
179  0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00,  // .accept.
180  0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70,  // ...accep
181  0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,  // t-charse
182  0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63,  // t....acc
183  0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,  // ept-enco
184  0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f,  // ding....
185  0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c,  // accept-l
186  0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00,  // anguage.
187  0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70,  // ...accep
188  0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73,  // t-ranges
189  0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00,  // ....age.
190  0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77,  // ...allow
191  0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68,  // ....auth
192  0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,  // orizatio
193  0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63,  // n....cac
194  0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72,  // he-contr
195  0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f,  // ol....co
196  0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,  // nnection
197  0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74,  // ....cont
198  0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65,  // ent-base
199  0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74,  // ....cont
200  0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,  // ent-enco
201  0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10,  // ding....
202  0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,  // content-
203  0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,  // language
204  0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74,  // ....cont
205  0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67,  // ent-leng
206  0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f,  // th....co
207  0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f,  // ntent-lo
208  0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00,  // cation..
209  0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,  // ..conten
210  0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00,  // t-md5...
211  0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,  // .content
212  0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00,  // -range..
213  0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,  // ..conten
214  0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00,  // t-type..
215  0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00,  // ..date..
216  0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00,  // ..etag..
217  0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,  // ..expect
218  0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69,  // ....expi
219  0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66,  // res....f
220  0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68,  // rom....h
221  0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69,  // ost....i
222  0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00,  // f-match.
223  0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f,  // ...if-mo
224  0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73,  // dified-s
225  0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d,  // ince....
226  0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d,  // if-none-
227  0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00,  // match...
228  0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67,  // .if-rang
229  0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d,  // e....if-
230  0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,  // unmodifi
231  0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65,  // ed-since
232  0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74,  // ....last
233  0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,  // -modifie
234  0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63,  // d....loc
235  0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00,  // ation...
236  0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72,  // .max-for
237  0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00,  // wards...
238  0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00,  // .pragma.
239  0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79,  // ...proxy
240  0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,  // -authent
241  0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00,  // icate...
242  0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61,  // .proxy-a
243  0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61,  // uthoriza
244  0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05,  // tion....
245  0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00,  // range...
246  0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72,  // .referer
247  0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72,  // ....retr
248  0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00,  // y-after.
249  0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,  // ...serve
250  0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00,  // r....te.
251  0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c,  // ...trail
252  0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72,  // er....tr
253  0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65,  // ansfer-e
254  0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00,  // ncoding.
255  0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61,  // ...upgra
256  0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73,  // de....us
257  0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74,  // er-agent
258  0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79,  // ....vary
259  0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00,  // ....via.
260  0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69,  // ...warni
261  0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77,  // ng....ww
262  0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,  // w-authen
263  0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00,  // ticate..
264  0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,  // ..method
265  0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00,  // ....get.
266  0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,  // ...statu
267  0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30,  // s....200
268  0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76,  // .OK....v
269  0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00,  // ersion..
270  0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31,  // ..HTTP.1
271  0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72,  // .1....ur
272  0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62,  // l....pub
273  0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73,  // lic....s
274  0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69,  // et-cooki
275  0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65,  // e....kee
276  0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00,  // p-alive.
277  0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69,  // ...origi
278  0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32,  // n1001012
279  0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35,  // 01202205
280  0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30,  // 20630030
281  0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33,  // 23033043
282  0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37,  // 05306307
283  0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30,  // 40240540
284  0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34,  // 64074084
285  0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31,  // 09410411
286  0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31,  // 41241341
287  0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34,  // 44154164
288  0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34,  // 17502504
289  0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e,  // 505203.N
290  0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f,  // on-Autho
291  0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65,  // ritative
292  0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61,  // .Informa
293  0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20,  // tion204.
294  0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65,  // No.Conte
295  0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f,  // nt301.Mo
296  0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d,  // ved.Perm
297  0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34,  // anently4
298  0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52,  // 00.Bad.R
299  0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30,  // equest40
300  0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68,  // 1.Unauth
301  0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30,  // orized40
302  0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64,  // 3.Forbid
303  0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e,  // den404.N
304  0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64,  // ot.Found
305  0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65,  // 500.Inte
306  0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72,  // rnal.Ser
307  0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f,  // ver.Erro
308  0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74,  // r501.Not
309  0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65,  // .Impleme
310  0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20,  // nted503.
311  0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20,  // Service.
312  0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,  // Unavaila
313  0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46,  // bleJan.F
314  0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41,  // eb.Mar.A
315  0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a,  // pr.May.J
316  0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41,  // un.Jul.A
317  0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20,  // ug.Sept.
318  0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20,  // Oct.Nov.
319  0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30,  // Dec.00.0
320  0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e,  // 0.00.Mon
321  0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57,  // ..Tue..W
322  0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c,  // ed..Thu.
323  0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61,  // .Fri..Sa
324  0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20,  // t..Sun..
325  0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b,  // GMTchunk
326  0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f,  // ed.text.
327  0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61,  // html.ima
328  0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69,  // ge.png.i
329  0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67,  // mage.jpg
330  0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67,  // .image.g
331  0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,  // if.appli
332  0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,  // cation.x
333  0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,  // ml.appli
334  0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,  // cation.x
335  0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c,  // html.xml
336  0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c,  // .text.pl
337  0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74,  // ain.text
338  0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72,  // .javascr
339  0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c,  // ipt.publ
340  0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,  // icprivat
341  0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65,  // emax-age
342  0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65,  // .gzip.de
343  0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64,  // flate.sd
344  0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,  // chcharse
345  0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63,  // t.utf-8c
346  0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69,  // harset.i
347  0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d,  // so-8859-
348  0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a,  // 1.utf-..
349  0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e         // .enq.0.
350};
351const int kV3DictionarySize = arraysize(kV3Dictionary);
352
353// Note: all protocol data structures are on-the-wire format.  That means that
354//       data is stored in network-normalized order.  Readers must use the
355//       accessors provided or call ntohX() functions.
356
357// Types of Spdy Control Frames.
358enum SpdyControlType {
359  SYN_STREAM = 1,
360  SYN_REPLY,
361  RST_STREAM,
362  SETTINGS,
363  NOOP,  // Because it is valid in SPDY/2, kept for identifiability/enum order.
364  PING,
365  GOAWAY,
366  HEADERS,
367  WINDOW_UPDATE,
368  CREDENTIAL,
369  NUM_CONTROL_FRAME_TYPES
370};
371
372// Flags on data packets.
373enum SpdyDataFlags {
374  DATA_FLAG_NONE = 0,
375  DATA_FLAG_FIN = 1,
376};
377
378// Flags on control packets
379enum SpdyControlFlags {
380  CONTROL_FLAG_NONE = 0,
381  CONTROL_FLAG_FIN = 1,
382  CONTROL_FLAG_UNIDIRECTIONAL = 2
383};
384
385// Flags on the SETTINGS control frame.
386enum SpdySettingsControlFlags {
387  SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS = 0x1
388};
389
390// Flags for settings within a SETTINGS frame.
391enum SpdySettingsFlags {
392  SETTINGS_FLAG_NONE = 0x0,
393  SETTINGS_FLAG_PLEASE_PERSIST = 0x1,
394  SETTINGS_FLAG_PERSISTED = 0x2
395};
396
397// List of known settings.
398enum SpdySettingsIds {
399  SETTINGS_UPLOAD_BANDWIDTH = 0x1,
400  SETTINGS_DOWNLOAD_BANDWIDTH = 0x2,
401  // Network round trip time in milliseconds.
402  SETTINGS_ROUND_TRIP_TIME = 0x3,
403  SETTINGS_MAX_CONCURRENT_STREAMS = 0x4,
404  // TCP congestion window in packets.
405  SETTINGS_CURRENT_CWND = 0x5,
406  // Downstream byte retransmission rate in percentage.
407  SETTINGS_DOWNLOAD_RETRANS_RATE = 0x6,
408  // Initial window size in bytes
409  SETTINGS_INITIAL_WINDOW_SIZE = 0x7
410};
411
412// Status codes, as used in control frames (primarily RST_STREAM).
413// TODO(hkhalil): Rename to SpdyRstStreamStatus
414enum SpdyStatusCodes {
415  INVALID = 0,
416  PROTOCOL_ERROR = 1,
417  INVALID_STREAM = 2,
418  REFUSED_STREAM = 3,
419  UNSUPPORTED_VERSION = 4,
420  CANCEL = 5,
421  INTERNAL_ERROR = 6,
422  FLOW_CONTROL_ERROR = 7,
423  STREAM_IN_USE = 8,
424  STREAM_ALREADY_CLOSED = 9,
425  INVALID_CREDENTIALS = 10,
426  FRAME_TOO_LARGE = 11,
427  NUM_STATUS_CODES = 12
428};
429
430enum SpdyGoAwayStatus {
431  GOAWAY_INVALID = -1,
432  GOAWAY_OK = 0,
433  GOAWAY_PROTOCOL_ERROR = 1,
434  GOAWAY_INTERNAL_ERROR = 2,
435  GOAWAY_NUM_STATUS_CODES = 3
436};
437
438// A SPDY stream id is a 31 bit entity.
439typedef uint32 SpdyStreamId;
440
441// A SPDY priority is a number between 0 and 7 (inclusive).
442// SPDY priority range is version-dependant. For SPDY 2 and below, priority is a
443// number between 0 and 3.
444typedef uint8 SpdyPriority;
445
446// -------------------------------------------------------------------------
447// These structures mirror the protocol structure definitions.
448
449// For the control data structures, we pack so that sizes match the
450// protocol over-the-wire sizes.
451#pragma pack(push)
452#pragma pack(1)
453
454// A special structure for the 8 bit flags and 24 bit length fields.
455union FlagsAndLength {
456  uint8 flags_[4];  // 8 bits
457  uint32 length_;   // 24 bits
458};
459
460// The basic SPDY Frame structure.
461struct SpdyFrameBlock {
462  union {
463    struct {
464      uint16 version_;
465      uint16 type_;
466    } control_;
467    struct {
468      SpdyStreamId stream_id_;
469    } data_;
470  };
471  FlagsAndLength flags_length_;
472};
473
474// A SYN_STREAM Control Frame structure.
475struct SpdySynStreamControlFrameBlock : SpdyFrameBlock {
476  SpdyStreamId stream_id_;
477  SpdyStreamId associated_stream_id_;
478  SpdyPriority priority_;
479  uint8 credential_slot_;
480};
481
482// A SYN_REPLY Control Frame structure.
483struct SpdySynReplyControlFrameBlock : SpdyFrameBlock {
484  SpdyStreamId stream_id_;
485};
486
487// A RST_STREAM Control Frame structure.
488struct SpdyRstStreamControlFrameBlock : SpdyFrameBlock {
489  SpdyStreamId stream_id_;
490  uint32 status_;
491};
492
493// A SETTINGS Control Frame structure.
494struct SpdySettingsControlFrameBlock : SpdyFrameBlock {
495  uint32 num_entries_;
496  // Variable data here.
497};
498
499// A PING Control Frame structure.
500struct SpdyPingControlFrameBlock : SpdyFrameBlock {
501  uint32 unique_id_;
502};
503
504// TODO(avd): remove this struct
505// A CREDENTIAL Control Frame structure.
506struct SpdyCredentialControlFrameBlock : SpdyFrameBlock {
507  uint16 slot_;
508  uint32 proof_len_;
509  // Variable data here.
510  // proof data
511  // for each certificate: unit32 certificate_len + certificate_data[i]
512};
513
514// A GOAWAY Control Frame structure.
515struct SpdyGoAwayControlFrameBlock : SpdyFrameBlock {
516  SpdyStreamId last_accepted_stream_id_;
517  SpdyGoAwayStatus status_;
518};
519
520// A HEADERS Control Frame structure.
521struct SpdyHeadersControlFrameBlock : SpdyFrameBlock {
522  SpdyStreamId stream_id_;
523};
524
525// A WINDOW_UPDATE Control Frame structure
526struct SpdyWindowUpdateControlFrameBlock : SpdyFrameBlock {
527  SpdyStreamId stream_id_;
528  uint32 delta_window_size_;
529};
530
531#pragma pack(pop)
532
533// -------------------------------------------------------------------------
534// Wrapper classes for various SPDY frames.
535
536// All Spdy Frame types derive from this SpdyFrame class.
537class SpdyFrame {
538 public:
539  // Create a SpdyFrame for a given sized buffer.
540  explicit SpdyFrame(size_t size) : frame_(NULL), owns_buffer_(true) {
541    DCHECK_GE(size, sizeof(struct SpdyFrameBlock));
542    char* buffer = new char[size];
543    memset(buffer, 0, size);
544    frame_ = reinterpret_cast<struct SpdyFrameBlock*>(buffer);
545  }
546
547  // Create a SpdyFrame using a pre-created buffer.
548  // If |owns_buffer| is true, this class takes ownership of the buffer
549  // and will delete it on cleanup.  The buffer must have been created using
550  // new char[].
551  // If |owns_buffer| is false, the caller retains ownership of the buffer and
552  // is responsible for making sure the buffer outlives this frame.  In other
553  // words, this class does NOT create a copy of the buffer.
554  SpdyFrame(char* data, bool owns_buffer)
555      : frame_(reinterpret_cast<struct SpdyFrameBlock*>(data)),
556        owns_buffer_(owns_buffer) {
557    DCHECK(frame_);
558  }
559
560  ~SpdyFrame() {
561    if (owns_buffer_) {
562      char* buffer = reinterpret_cast<char*>(frame_);
563      delete [] buffer;
564    }
565    frame_ = NULL;
566  }
567
568  // Provides access to the frame bytes, which is a buffer containing
569  // the frame packed as expected for sending over the wire.
570  char* data() const { return reinterpret_cast<char*>(frame_); }
571
572  uint8 flags() const { return frame_->flags_length_.flags_[0]; }
573  void set_flags(uint8 flags) { frame_->flags_length_.flags_[0] = flags; }
574
575  uint32 length() const {
576    return ntohl(frame_->flags_length_.length_) & kLengthMask;
577  }
578
579  void set_length(uint32 length) {
580    DCHECK_EQ(0u, (length & ~kLengthMask));
581    length = htonl(length & kLengthMask);
582    frame_->flags_length_.length_ = flags() | length;
583  }
584
585  bool is_control_frame() const {
586    return (ntohs(frame_->control_.version_) & kControlFlagMask) ==
587        kControlFlagMask;
588  }
589
590  // The size of the SpdyFrameBlock structure.
591  // Every SpdyFrame* class has a static size() method for accessing
592  // the size of the data structure which will be sent over the wire.
593  // Note:  this is not the same as sizeof(SpdyFrame).
594  enum { kHeaderSize = sizeof(struct SpdyFrameBlock) };
595
596 protected:
597  SpdyFrameBlock* frame_;
598
599 private:
600  bool owns_buffer_;
601  DISALLOW_COPY_AND_ASSIGN(SpdyFrame);
602};
603
604// A Data Frame.
605class SpdyDataFrame : public SpdyFrame {
606 public:
607  SpdyDataFrame() : SpdyFrame(size()) {}
608  SpdyDataFrame(char* data, bool owns_buffer)
609      : SpdyFrame(data, owns_buffer) {}
610
611  SpdyStreamId stream_id() const {
612    return ntohl(frame_->data_.stream_id_) & kStreamIdMask;
613  }
614
615  // Note that setting the stream id sets the control bit to false.
616  // As stream id should always be set, this means the control bit
617  // should always be set correctly.
618  void set_stream_id(SpdyStreamId id) {
619    DCHECK_EQ(0u, (id & ~kStreamIdMask));
620    frame_->data_.stream_id_ = htonl(id & kStreamIdMask);
621  }
622
623  // Returns the size of the SpdyFrameBlock structure.
624  // Note: this is not the size of the SpdyDataFrame class.
625  static size_t size() { return SpdyFrame::kHeaderSize; }
626
627  const char* payload() const {
628    return reinterpret_cast<const char*>(frame_) + size();
629  }
630
631 private:
632  DISALLOW_COPY_AND_ASSIGN(SpdyDataFrame);
633};
634
635// A Control Frame.
636class SpdyControlFrame : public SpdyFrame {
637 public:
638  explicit SpdyControlFrame(size_t size) : SpdyFrame(size) {}
639  SpdyControlFrame(char* data, bool owns_buffer)
640      : SpdyFrame(data, owns_buffer) {}
641
642  // Callers can use this method to check if the frame appears to be a valid
643  // frame.  Does not guarantee that there are no errors.
644  bool AppearsToBeAValidControlFrame() const {
645    // Right now we only check if the frame has an out-of-bounds type.
646    uint16 type = ntohs(block()->control_.type_);
647    // NOOP is not a 'valid' control frame in SPDY/3 and beyond.
648    return type >= SYN_STREAM &&
649        type < NUM_CONTROL_FRAME_TYPES &&
650        (version() == 2 || type != NOOP);
651  }
652
653  uint16 version() const {
654    const int kVersionMask = 0x7fff;
655    return ntohs(block()->control_.version_) & kVersionMask;
656  }
657
658  void set_version(uint16 version) {
659    const uint16 kControlBit = 0x80;
660    DCHECK_EQ(0, version & kControlBit);
661    mutable_block()->control_.version_ = kControlBit | htons(version);
662  }
663
664  SpdyControlType type() const {
665    uint16 type = ntohs(block()->control_.type_);
666    LOG_IF(DFATAL, type < SYN_STREAM || type >= NUM_CONTROL_FRAME_TYPES)
667        << "Invalid control frame type " << type;
668    return static_cast<SpdyControlType>(type);
669  }
670
671  void set_type(SpdyControlType type) {
672    DCHECK(type >= SYN_STREAM && type < NUM_CONTROL_FRAME_TYPES);
673    mutable_block()->control_.type_ = htons(type);
674  }
675
676  // Returns true if this control frame is of a type that has a header block,
677  // otherwise it returns false.
678  bool has_header_block() const {
679    return type() == SYN_STREAM || type() == SYN_REPLY || type() == HEADERS;
680  }
681
682 private:
683  const struct SpdyFrameBlock* block() const {
684    return frame_;
685  }
686  struct SpdyFrameBlock* mutable_block() {
687    return frame_;
688  }
689  DISALLOW_COPY_AND_ASSIGN(SpdyControlFrame);
690};
691
692// A SYN_STREAM frame.
693class SpdySynStreamControlFrame : public SpdyControlFrame {
694 public:
695  SpdySynStreamControlFrame() : SpdyControlFrame(size()) {}
696  SpdySynStreamControlFrame(char* data, bool owns_buffer)
697      : SpdyControlFrame(data, owns_buffer) {}
698
699  SpdyStreamId stream_id() const {
700    return ntohl(block()->stream_id_) & kStreamIdMask;
701  }
702
703  void set_stream_id(SpdyStreamId id) {
704    mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
705  }
706
707  SpdyStreamId associated_stream_id() const {
708    return ntohl(block()->associated_stream_id_) & kStreamIdMask;
709  }
710
711  void set_associated_stream_id(SpdyStreamId id) {
712    mutable_block()->associated_stream_id_ = htonl(id & kStreamIdMask);
713  }
714
715  SpdyPriority priority() const {
716    if (version() < 3) {
717      return (block()->priority_ & kSpdy2PriorityMask) >> 6;
718    } else {
719      return (block()->priority_ & kSpdy3PriorityMask) >> 5;
720    }
721  }
722
723  uint8 credential_slot() const {
724    if (version() < 3) {
725      return 0;
726    } else {
727      return block()->credential_slot_;
728    }
729  }
730
731  void set_credential_slot(uint8 credential_slot) {
732    DCHECK(version() >= 3);
733    mutable_block()->credential_slot_ = credential_slot;
734  }
735
736  // The number of bytes in the header block beyond the frame header length.
737  int header_block_len() const {
738    return length() - (size() - SpdyFrame::kHeaderSize);
739  }
740
741  const char* header_block() const {
742    return reinterpret_cast<const char*>(block()) + size();
743  }
744
745  // Returns the size of the SpdySynStreamControlFrameBlock structure.
746  // Note: this is not the size of the SpdySynStreamControlFrame class.
747  static size_t size() { return sizeof(SpdySynStreamControlFrameBlock); }
748
749 private:
750  const struct SpdySynStreamControlFrameBlock* block() const {
751    return static_cast<SpdySynStreamControlFrameBlock*>(frame_);
752  }
753  struct SpdySynStreamControlFrameBlock* mutable_block() {
754    return static_cast<SpdySynStreamControlFrameBlock*>(frame_);
755  }
756  DISALLOW_COPY_AND_ASSIGN(SpdySynStreamControlFrame);
757};
758
759// A SYN_REPLY frame.
760class SpdySynReplyControlFrame : public SpdyControlFrame {
761 public:
762  SpdySynReplyControlFrame() : SpdyControlFrame(size()) {}
763  SpdySynReplyControlFrame(char* data, bool owns_buffer)
764      : SpdyControlFrame(data, owns_buffer) {}
765
766  SpdyStreamId stream_id() const {
767    return ntohl(block()->stream_id_) & kStreamIdMask;
768  }
769
770  void set_stream_id(SpdyStreamId id) {
771    mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
772  }
773
774  int header_block_len() const {
775    size_t header_block_len = length() - (size() - SpdyFrame::kHeaderSize);
776    // SPDY 2 had 2 bytes of unused space preceeding the header block.
777    if (version() < 3) {
778      header_block_len -= 2;
779    }
780    return header_block_len;
781  }
782
783  const char* header_block() const {
784    const char* header_block = reinterpret_cast<const char*>(block()) + size();
785    // SPDY 2 had 2 bytes of unused space preceeding the header block.
786    if (version() < 3) {
787      header_block += 2;
788    }
789    return header_block;
790  }
791
792  // Returns the size of the SpdySynReplyControlFrameBlock structure.
793  // Note: this is not the size of the SpdySynReplyControlFrame class.
794  static size_t size() { return sizeof(SpdySynReplyControlFrameBlock); }
795
796 private:
797  const struct SpdySynReplyControlFrameBlock* block() const {
798    return static_cast<SpdySynReplyControlFrameBlock*>(frame_);
799  }
800  struct SpdySynReplyControlFrameBlock* mutable_block() {
801    return static_cast<SpdySynReplyControlFrameBlock*>(frame_);
802  }
803  DISALLOW_COPY_AND_ASSIGN(SpdySynReplyControlFrame);
804};
805
806// A RST_STREAM frame.
807class SpdyRstStreamControlFrame : public SpdyControlFrame {
808 public:
809  SpdyRstStreamControlFrame() : SpdyControlFrame(size()) {}
810  SpdyRstStreamControlFrame(char* data, bool owns_buffer)
811      : SpdyControlFrame(data, owns_buffer) {}
812
813  SpdyStreamId stream_id() const {
814    return ntohl(block()->stream_id_) & kStreamIdMask;
815  }
816
817  void set_stream_id(SpdyStreamId id) {
818    mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
819  }
820
821  SpdyStatusCodes status() const {
822    SpdyStatusCodes status =
823        static_cast<SpdyStatusCodes>(ntohl(block()->status_));
824    if (status < INVALID || status >= NUM_STATUS_CODES) {
825      status = INVALID;
826    }
827    return status;
828  }
829  void set_status(SpdyStatusCodes status) {
830    mutable_block()->status_ = htonl(static_cast<uint32>(status));
831  }
832
833  // Returns the size of the SpdyRstStreamControlFrameBlock structure.
834  // Note: this is not the size of the SpdyRstStreamControlFrame class.
835  static size_t size() { return sizeof(SpdyRstStreamControlFrameBlock); }
836
837 private:
838  const struct SpdyRstStreamControlFrameBlock* block() const {
839    return static_cast<SpdyRstStreamControlFrameBlock*>(frame_);
840  }
841  struct SpdyRstStreamControlFrameBlock* mutable_block() {
842    return static_cast<SpdyRstStreamControlFrameBlock*>(frame_);
843  }
844  DISALLOW_COPY_AND_ASSIGN(SpdyRstStreamControlFrame);
845};
846
847class SpdySettingsControlFrame : public SpdyControlFrame {
848 public:
849  SpdySettingsControlFrame() : SpdyControlFrame(size()) {}
850  SpdySettingsControlFrame(char* data, bool owns_buffer)
851      : SpdyControlFrame(data, owns_buffer) {}
852
853  uint32 num_entries() const {
854    return ntohl(block()->num_entries_);
855  }
856
857  void set_num_entries(int val) {
858    mutable_block()->num_entries_ = htonl(val);
859  }
860
861  int header_block_len() const {
862    return length() - (size() - SpdyFrame::kHeaderSize);
863  }
864
865  const char* header_block() const {
866    return reinterpret_cast<const char*>(block()) + size();
867  }
868
869  // Returns the size of the SpdySettingsControlFrameBlock structure.
870  // Note: this is not the size of the SpdySettingsControlFrameBlock class.
871  static size_t size() { return sizeof(SpdySettingsControlFrameBlock); }
872
873 private:
874  const struct SpdySettingsControlFrameBlock* block() const {
875    return static_cast<SpdySettingsControlFrameBlock*>(frame_);
876  }
877  struct SpdySettingsControlFrameBlock* mutable_block() {
878    return static_cast<SpdySettingsControlFrameBlock*>(frame_);
879  }
880  DISALLOW_COPY_AND_ASSIGN(SpdySettingsControlFrame);
881};
882
883class SpdyPingControlFrame : public SpdyControlFrame {
884 public:
885  SpdyPingControlFrame() : SpdyControlFrame(size()) {}
886  SpdyPingControlFrame(char* data, bool owns_buffer)
887      : SpdyControlFrame(data, owns_buffer) {}
888
889  uint32 unique_id() const {
890    return ntohl(block()->unique_id_);
891  }
892
893  void set_unique_id(uint32 unique_id) {
894    mutable_block()->unique_id_ = htonl(unique_id);
895  }
896
897  static size_t size() { return sizeof(SpdyPingControlFrameBlock); }
898
899 private:
900  const struct SpdyPingControlFrameBlock* block() const {
901    return static_cast<SpdyPingControlFrameBlock*>(frame_);
902  }
903  struct SpdyPingControlFrameBlock* mutable_block() {
904    return static_cast<SpdyPingControlFrameBlock*>(frame_);
905  }
906};
907
908class SpdyCredentialControlFrame : public SpdyControlFrame {
909 public:
910  SpdyCredentialControlFrame() : SpdyControlFrame(size()) {}
911  SpdyCredentialControlFrame(char* data, bool owns_buffer)
912      : SpdyControlFrame(data, owns_buffer) {}
913
914  const char* payload() const {
915    return reinterpret_cast<const char*>(block()) + SpdyFrame::kHeaderSize;
916  }
917
918  static size_t size() { return sizeof(SpdyCredentialControlFrameBlock); }
919
920 private:
921  const struct SpdyCredentialControlFrameBlock* block() const {
922    return static_cast<SpdyCredentialControlFrameBlock*>(frame_);
923  }
924  DISALLOW_COPY_AND_ASSIGN(SpdyCredentialControlFrame);
925};
926
927class SpdyGoAwayControlFrame : public SpdyControlFrame {
928 public:
929  SpdyGoAwayControlFrame() : SpdyControlFrame(size()) {}
930  SpdyGoAwayControlFrame(char* data, bool owns_buffer)
931      : SpdyControlFrame(data, owns_buffer) {}
932
933  SpdyStreamId last_accepted_stream_id() const {
934    return ntohl(block()->last_accepted_stream_id_) & kStreamIdMask;
935  }
936
937  SpdyGoAwayStatus status() const {
938    if (version() < 3) {
939      LOG(DFATAL) << "Attempted to access status of SPDY 2 GOAWAY.";
940      return GOAWAY_INVALID;
941    } else {
942      uint32 status = ntohl(block()->status_);
943      if (status >= GOAWAY_NUM_STATUS_CODES) {
944        return GOAWAY_INVALID;
945      } else {
946        return static_cast<SpdyGoAwayStatus>(status);
947      }
948    }
949  }
950
951  void set_last_accepted_stream_id(SpdyStreamId id) {
952    mutable_block()->last_accepted_stream_id_ = htonl(id & kStreamIdMask);
953  }
954
955  static size_t size() { return sizeof(SpdyGoAwayControlFrameBlock); }
956
957 private:
958  const struct SpdyGoAwayControlFrameBlock* block() const {
959    return static_cast<SpdyGoAwayControlFrameBlock*>(frame_);
960  }
961  struct SpdyGoAwayControlFrameBlock* mutable_block() {
962    return static_cast<SpdyGoAwayControlFrameBlock*>(frame_);
963  }
964  DISALLOW_COPY_AND_ASSIGN(SpdyGoAwayControlFrame);
965};
966
967// A HEADERS frame.
968class SpdyHeadersControlFrame : public SpdyControlFrame {
969 public:
970  SpdyHeadersControlFrame() : SpdyControlFrame(size()) {}
971  SpdyHeadersControlFrame(char* data, bool owns_buffer)
972      : SpdyControlFrame(data, owns_buffer) {}
973
974  SpdyStreamId stream_id() const {
975    return ntohl(block()->stream_id_) & kStreamIdMask;
976  }
977
978  void set_stream_id(SpdyStreamId id) {
979    mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
980  }
981
982  // The number of bytes in the header block beyond the frame header length.
983  int header_block_len() const {
984    size_t header_block_len = length() - (size() - SpdyFrame::kHeaderSize);
985    // SPDY 2 had 2 bytes of unused space preceeding the header block.
986    if (version() < 3) {
987      header_block_len -= 2;
988    }
989    return header_block_len;
990  }
991
992  const char* header_block() const {
993    const char* header_block = reinterpret_cast<const char*>(block()) + size();
994    // SPDY 2 had 2 bytes of unused space preceeding the header block.
995    if (version() < 3) {
996      header_block += 2;
997    }
998    return header_block;
999  }
1000
1001  // Returns the size of the SpdyHeadersControlFrameBlock structure.
1002  // Note: this is not the size of the SpdyHeadersControlFrame class.
1003  static size_t size() { return sizeof(SpdyHeadersControlFrameBlock); }
1004
1005 private:
1006  const struct SpdyHeadersControlFrameBlock* block() const {
1007    return static_cast<SpdyHeadersControlFrameBlock*>(frame_);
1008  }
1009  struct SpdyHeadersControlFrameBlock* mutable_block() {
1010    return static_cast<SpdyHeadersControlFrameBlock*>(frame_);
1011  }
1012  DISALLOW_COPY_AND_ASSIGN(SpdyHeadersControlFrame);
1013};
1014
1015// A WINDOW_UPDATE frame.
1016class SpdyWindowUpdateControlFrame : public SpdyControlFrame {
1017 public:
1018  SpdyWindowUpdateControlFrame() : SpdyControlFrame(size()) {}
1019  SpdyWindowUpdateControlFrame(char* data, bool owns_buffer)
1020      : SpdyControlFrame(data, owns_buffer) {}
1021
1022  SpdyStreamId stream_id() const {
1023    return ntohl(block()->stream_id_) & kStreamIdMask;
1024  }
1025
1026  void set_stream_id(SpdyStreamId id) {
1027    mutable_block()->stream_id_ = htonl(id & kStreamIdMask);
1028  }
1029
1030  uint32 delta_window_size() const {
1031    return ntohl(block()->delta_window_size_);
1032  }
1033
1034  void set_delta_window_size(uint32 delta_window_size) {
1035    mutable_block()->delta_window_size_ = htonl(delta_window_size);
1036  }
1037
1038  // Returns the size of the SpdyWindowUpdateControlFrameBlock structure.
1039  // Note: this is not the size of the SpdyWindowUpdateControlFrame class.
1040  static size_t size() { return sizeof(SpdyWindowUpdateControlFrameBlock); }
1041
1042 private:
1043  const struct SpdyWindowUpdateControlFrameBlock* block() const {
1044    return static_cast<SpdyWindowUpdateControlFrameBlock*>(frame_);
1045  }
1046  struct SpdyWindowUpdateControlFrameBlock* mutable_block() {
1047    return static_cast<SpdyWindowUpdateControlFrameBlock*>(frame_);
1048  }
1049
1050  DISALLOW_COPY_AND_ASSIGN(SpdyWindowUpdateControlFrame);
1051};
1052
1053}  // namespace net
1054
1055#endif  // NET_SPDY_SPDY_PROTOCOL_H_
1056