• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 2 and 3
6 // The SPDY 2 spec can be found at:
7 // http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft2
8 // The SPDY 3 spec can be found at:
9 // http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3
10 
11 #ifndef NET_SPDY_SPDY_PROTOCOL_H_
12 #define NET_SPDY_SPDY_PROTOCOL_H_
13 
14 #include <map>
15 #include <string>
16 #include <vector>
17 
18 #include "base/basictypes.h"
19 #include "base/compiler_specific.h"
20 #include "base/logging.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "base/strings/string_piece.h"
23 #include "base/sys_byteorder.h"
24 #include "net/base/net_export.h"
25 #include "net/spdy/spdy_bitmasks.h"
26 
27 namespace net {
28 
29 // The major versions of SPDY. Major version differences indicate
30 // framer-layer incompatibility, as opposed to minor version numbers
31 // which indicate application-layer incompatibility. It is guaranteed
32 // that the enum value SPDYn maps to the integer n.
33 enum SpdyMajorVersion {
34   SPDY2 = 2,
35   SPDY_MIN_VERSION = SPDY2,
36   SPDY3 = 3,
37   SPDY4 = 4,
38   SPDY_MAX_VERSION = SPDY4
39 };
40 
41 // A SPDY stream id is a 31 bit entity.
42 typedef uint32 SpdyStreamId;
43 
44 // Specifies the stream ID used to denote the current session (for
45 // flow control).
46 const SpdyStreamId kSessionFlowControlStreamId = 0;
47 
48 // Initial window size for a Spdy stream in bytes.
49 const int32 kSpdyStreamInitialWindowSize = 64 * 1024;  // 64 KBytes
50 
51 // Initial window size for a Spdy session in bytes.
52 const int32 kSpdySessionInitialWindowSize = 64 * 1024;  // 64 KBytes
53 
54 // Maximum window size for a Spdy stream or session.
55 const int32 kSpdyMaximumWindowSize = 0x7FFFFFFF;  // Max signed 32bit int
56 
57 // SPDY 2 dictionary.
58 // This is just a hacked dictionary to use for shrinking HTTP-like headers.
59 const char kV2Dictionary[] =
60   "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
61   "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
62   "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
63   "-agent10010120020120220320420520630030130230330430530630740040140240340440"
64   "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
65   "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
66   "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
67   "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
68   "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
69   "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
70   "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
71   "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
72   ".1statusversionurl";
73 const int kV2DictionarySize = arraysize(kV2Dictionary);
74 
75 // SPDY 3 dictionary.
76 const char kV3Dictionary[] = {
77   0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69,  // ....opti
78   0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68,  // ons....h
79   0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70,  // ead....p
80   0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70,  // ost....p
81   0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65,  // ut....de
82   0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05,  // lete....
83   0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00,  // trace...
84   0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00,  // .accept.
85   0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70,  // ...accep
86   0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,  // t-charse
87   0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63,  // t....acc
88   0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,  // ept-enco
89   0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f,  // ding....
90   0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c,  // accept-l
91   0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00,  // anguage.
92   0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70,  // ...accep
93   0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73,  // t-ranges
94   0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00,  // ....age.
95   0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77,  // ...allow
96   0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68,  // ....auth
97   0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,  // orizatio
98   0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63,  // n....cac
99   0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72,  // he-contr
100   0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f,  // ol....co
101   0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,  // nnection
102   0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74,  // ....cont
103   0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65,  // ent-base
104   0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74,  // ....cont
105   0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,  // ent-enco
106   0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10,  // ding....
107   0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,  // content-
108   0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,  // language
109   0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74,  // ....cont
110   0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67,  // ent-leng
111   0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f,  // th....co
112   0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f,  // ntent-lo
113   0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00,  // cation..
114   0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,  // ..conten
115   0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00,  // t-md5...
116   0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,  // .content
117   0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00,  // -range..
118   0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,  // ..conten
119   0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00,  // t-type..
120   0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00,  // ..date..
121   0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00,  // ..etag..
122   0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,  // ..expect
123   0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69,  // ....expi
124   0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66,  // res....f
125   0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68,  // rom....h
126   0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69,  // ost....i
127   0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00,  // f-match.
128   0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f,  // ...if-mo
129   0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73,  // dified-s
130   0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d,  // ince....
131   0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d,  // if-none-
132   0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00,  // match...
133   0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67,  // .if-rang
134   0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d,  // e....if-
135   0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,  // unmodifi
136   0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65,  // ed-since
137   0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74,  // ....last
138   0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,  // -modifie
139   0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63,  // d....loc
140   0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00,  // ation...
141   0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72,  // .max-for
142   0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00,  // wards...
143   0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00,  // .pragma.
144   0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79,  // ...proxy
145   0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,  // -authent
146   0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00,  // icate...
147   0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61,  // .proxy-a
148   0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61,  // uthoriza
149   0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05,  // tion....
150   0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00,  // range...
151   0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72,  // .referer
152   0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72,  // ....retr
153   0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00,  // y-after.
154   0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,  // ...serve
155   0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00,  // r....te.
156   0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c,  // ...trail
157   0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72,  // er....tr
158   0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65,  // ansfer-e
159   0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00,  // ncoding.
160   0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61,  // ...upgra
161   0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73,  // de....us
162   0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74,  // er-agent
163   0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79,  // ....vary
164   0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00,  // ....via.
165   0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69,  // ...warni
166   0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77,  // ng....ww
167   0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,  // w-authen
168   0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00,  // ticate..
169   0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,  // ..method
170   0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00,  // ....get.
171   0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,  // ...statu
172   0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30,  // s....200
173   0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76,  // .OK....v
174   0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00,  // ersion..
175   0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31,  // ..HTTP.1
176   0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72,  // .1....ur
177   0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62,  // l....pub
178   0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73,  // lic....s
179   0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69,  // et-cooki
180   0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65,  // e....kee
181   0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00,  // p-alive.
182   0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69,  // ...origi
183   0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32,  // n1001012
184   0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35,  // 01202205
185   0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30,  // 20630030
186   0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33,  // 23033043
187   0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37,  // 05306307
188   0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30,  // 40240540
189   0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34,  // 64074084
190   0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31,  // 09410411
191   0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31,  // 41241341
192   0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34,  // 44154164
193   0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34,  // 17502504
194   0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e,  // 505203.N
195   0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f,  // on-Autho
196   0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65,  // ritative
197   0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61,  // .Informa
198   0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20,  // tion204.
199   0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65,  // No.Conte
200   0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f,  // nt301.Mo
201   0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d,  // ved.Perm
202   0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34,  // anently4
203   0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52,  // 00.Bad.R
204   0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30,  // equest40
205   0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68,  // 1.Unauth
206   0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30,  // orized40
207   0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64,  // 3.Forbid
208   0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e,  // den404.N
209   0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64,  // ot.Found
210   0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65,  // 500.Inte
211   0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72,  // rnal.Ser
212   0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f,  // ver.Erro
213   0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74,  // r501.Not
214   0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65,  // .Impleme
215   0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20,  // nted503.
216   0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20,  // Service.
217   0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,  // Unavaila
218   0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46,  // bleJan.F
219   0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41,  // eb.Mar.A
220   0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a,  // pr.May.J
221   0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41,  // un.Jul.A
222   0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20,  // ug.Sept.
223   0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20,  // Oct.Nov.
224   0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30,  // Dec.00.0
225   0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e,  // 0.00.Mon
226   0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57,  // ..Tue..W
227   0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c,  // ed..Thu.
228   0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61,  // .Fri..Sa
229   0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20,  // t..Sun..
230   0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b,  // GMTchunk
231   0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f,  // ed.text.
232   0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61,  // html.ima
233   0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69,  // ge.png.i
234   0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67,  // mage.jpg
235   0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67,  // .image.g
236   0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,  // if.appli
237   0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,  // cation.x
238   0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,  // ml.appli
239   0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,  // cation.x
240   0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c,  // html.xml
241   0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c,  // .text.pl
242   0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74,  // ain.text
243   0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72,  // .javascr
244   0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c,  // ipt.publ
245   0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,  // icprivat
246   0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65,  // emax-age
247   0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65,  // .gzip.de
248   0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64,  // flate.sd
249   0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,  // chcharse
250   0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63,  // t.utf-8c
251   0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69,  // harset.i
252   0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d,  // so-8859-
253   0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a,  // 1.utf-..
254   0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e         // .enq.0.
255 };
256 const int kV3DictionarySize = arraysize(kV3Dictionary);
257 
258 // The HTTP/2 connection header prefix, which must be the first bytes
259 // sent by the client upon starting an HTTP/2 connection, and which
260 // must be followed by a SETTINGS frame.
261 //
262 // Equivalent to the string "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
263 // (without the null terminator).
264 const char kHttp2ConnectionHeaderPrefix[] = {
265   0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54,  // PRI * HT
266   0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a,  // TP/2.0..
267   0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a   // ..SM....
268 };
269 const int kHttp2ConnectionHeaderPrefixSize =
270     arraysize(kHttp2ConnectionHeaderPrefix);
271 
272 // Types of SPDY frames.
273 enum SpdyFrameType {
274   DATA = 0,
275   SYN_STREAM = 1,
276   FIRST_CONTROL_TYPE = SYN_STREAM,
277   SYN_REPLY,
278   RST_STREAM,
279   SETTINGS,
280   NOOP,  // Because it is valid in SPDY/2, kept for identifiability/enum order.
281   PING,
282   GOAWAY,
283   HEADERS,
284   WINDOW_UPDATE,
285   CREDENTIAL,
286   BLOCKED,
287   PUSH_PROMISE,
288   LAST_CONTROL_TYPE = PUSH_PROMISE
289 };
290 
291 // Flags on data packets.
292 enum SpdyDataFlags {
293   DATA_FLAG_NONE = 0,
294   DATA_FLAG_FIN = 1,
295 };
296 
297 // Flags on control packets
298 enum SpdyControlFlags {
299   CONTROL_FLAG_NONE = 0,
300   CONTROL_FLAG_FIN = 1,
301   CONTROL_FLAG_UNIDIRECTIONAL = 2
302 };
303 
304 // Flags on the SETTINGS control frame.
305 enum SpdySettingsControlFlags {
306   SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS = 0x1
307 };
308 
309 // Flags for settings within a SETTINGS frame.
310 enum SpdySettingsFlags {
311   SETTINGS_FLAG_NONE = 0x0,
312   SETTINGS_FLAG_PLEASE_PERSIST = 0x1,
313   SETTINGS_FLAG_PERSISTED = 0x2
314 };
315 
316 // List of known settings.
317 enum SpdySettingsIds {
318   SETTINGS_UPLOAD_BANDWIDTH = 0x1,
319   SETTINGS_DOWNLOAD_BANDWIDTH = 0x2,
320   // Network round trip time in milliseconds.
321   SETTINGS_ROUND_TRIP_TIME = 0x3,
322   SETTINGS_MAX_CONCURRENT_STREAMS = 0x4,
323   // TCP congestion window in packets.
324   SETTINGS_CURRENT_CWND = 0x5,
325   // Downstream byte retransmission rate in percentage.
326   SETTINGS_DOWNLOAD_RETRANS_RATE = 0x6,
327   // Initial window size in bytes
328   SETTINGS_INITIAL_WINDOW_SIZE = 0x7
329 };
330 
331 // Status codes for RST_STREAM frames.
332 enum SpdyRstStreamStatus {
333   RST_STREAM_INVALID = 0,
334   RST_STREAM_PROTOCOL_ERROR = 1,
335   RST_STREAM_INVALID_STREAM = 2,
336   RST_STREAM_REFUSED_STREAM = 3,
337   RST_STREAM_UNSUPPORTED_VERSION = 4,
338   RST_STREAM_CANCEL = 5,
339   RST_STREAM_INTERNAL_ERROR = 6,
340   RST_STREAM_FLOW_CONTROL_ERROR = 7,
341   RST_STREAM_STREAM_IN_USE = 8,
342   RST_STREAM_STREAM_ALREADY_CLOSED = 9,
343   RST_STREAM_INVALID_CREDENTIALS = 10,
344   RST_STREAM_FRAME_TOO_LARGE = 11,
345   RST_STREAM_NUM_STATUS_CODES = 12
346 };
347 
348 // Status codes for GOAWAY frames.
349 enum SpdyGoAwayStatus {
350   GOAWAY_INVALID = -1,
351   GOAWAY_OK = 0,
352   GOAWAY_PROTOCOL_ERROR = 1,
353   GOAWAY_INTERNAL_ERROR = 2,
354   GOAWAY_NUM_STATUS_CODES = 3
355 };
356 
357 // A SPDY priority is a number between 0 and 7 (inclusive).
358 // SPDY priority range is version-dependant. For SPDY 2 and below, priority is a
359 // number between 0 and 3.
360 typedef uint8 SpdyPriority;
361 
362 typedef uint8 SpdyCredentialSlot;
363 
364 typedef std::map<std::string, std::string> SpdyNameValueBlock;
365 
366 typedef uint32 SpdyPingId;
367 
368 class SpdyFrame;
369 typedef SpdyFrame SpdySerializedFrame;
370 
371 class SpdyFrameVisitor;
372 
373 // Intermediate representation for SPDY frames.
374 // TODO(hkhalil): Rename this class to SpdyFrame when the existing SpdyFrame is
375 // gone.
376 class SpdyFrameIR {
377  public:
~SpdyFrameIR()378   virtual ~SpdyFrameIR() {}
379 
380   virtual void Visit(SpdyFrameVisitor* visitor) const = 0;
381 
382  protected:
SpdyFrameIR()383   SpdyFrameIR() {}
384 
385  private:
386   DISALLOW_COPY_AND_ASSIGN(SpdyFrameIR);
387 };
388 
389 // Abstract class intended to be inherited by IRs that have a stream associated
390 // to them.
391 class SpdyFrameWithStreamIdIR : public SpdyFrameIR {
392  public:
~SpdyFrameWithStreamIdIR()393   virtual ~SpdyFrameWithStreamIdIR() {}
stream_id()394   SpdyStreamId stream_id() const { return stream_id_; }
set_stream_id(SpdyStreamId stream_id)395   void set_stream_id(SpdyStreamId stream_id) {
396     DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
397     stream_id_ = stream_id;
398   }
399 
400  protected:
SpdyFrameWithStreamIdIR(SpdyStreamId stream_id)401   explicit SpdyFrameWithStreamIdIR(SpdyStreamId stream_id) {
402     set_stream_id(stream_id);
403   }
404 
405  private:
406   SpdyStreamId stream_id_;
407 
408   DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithStreamIdIR);
409 };
410 
411 // Abstract class intended to be inherited by IRs that have the option of a FIN
412 // flag. Implies SpdyFrameWithStreamIdIR.
413 class SpdyFrameWithFinIR : public SpdyFrameWithStreamIdIR {
414  public:
~SpdyFrameWithFinIR()415   virtual ~SpdyFrameWithFinIR() {}
fin()416   bool fin() const { return fin_; }
set_fin(bool fin)417   void set_fin(bool fin) { fin_ = fin; }
418 
419  protected:
SpdyFrameWithFinIR(SpdyStreamId stream_id)420   explicit SpdyFrameWithFinIR(SpdyStreamId stream_id)
421       : SpdyFrameWithStreamIdIR(stream_id),
422         fin_(false) {}
423 
424  private:
425   bool fin_;
426 
427   DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithFinIR);
428 };
429 
430 // Abstract class intended to be inherited by IRs that contain a name-value
431 // block. Implies SpdyFrameWithFinIR.
432 class NET_EXPORT_PRIVATE SpdyFrameWithNameValueBlockIR
NON_EXPORTED_BASE(SpdyFrameWithFinIR)433     : public NON_EXPORTED_BASE(SpdyFrameWithFinIR) {
434  public:
435   const SpdyNameValueBlock& name_value_block() const {
436     return name_value_block_;
437   }
438   SpdyNameValueBlock* GetMutableNameValueBlock() { return &name_value_block_; }
439   void SetHeader(const base::StringPiece& name,
440                  const base::StringPiece& value) {
441     name_value_block_[name.as_string()] = value.as_string();
442   }
443 
444  protected:
445   explicit SpdyFrameWithNameValueBlockIR(SpdyStreamId stream_id);
446   virtual ~SpdyFrameWithNameValueBlockIR();
447 
448  private:
449   SpdyNameValueBlock name_value_block_;
450 
451   DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithNameValueBlockIR);
452 };
453 
454 class NET_EXPORT_PRIVATE SpdyDataIR
NON_EXPORTED_BASE(SpdyFrameWithFinIR)455     : public NON_EXPORTED_BASE(SpdyFrameWithFinIR) {
456  public:
457   // Performs deep copy on data.
458   SpdyDataIR(SpdyStreamId stream_id, const base::StringPiece& data);
459 
460   // Use in conjunction with SetDataShallow() for shallow-copy on data.
461   explicit SpdyDataIR(SpdyStreamId stream_id);
462 
463   virtual ~SpdyDataIR();
464 
465   base::StringPiece data() const { return data_; }
466 
467   // Deep-copy of data (keep private copy).
468   void SetDataDeep(const base::StringPiece& data) {
469     data_store_.reset(new std::string(data.data(), data.length()));
470     data_ = *(data_store_.get());
471   }
472 
473   // Shallow-copy of data (do not keep private copy).
474   void SetDataShallow(const base::StringPiece& data) {
475     data_store_.reset();
476     data_ = data;
477   }
478 
479   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
480 
481  private:
482   // Used to store data that this SpdyDataIR should own.
483   scoped_ptr<std::string> data_store_;
484   base::StringPiece data_;
485 
486   DISALLOW_COPY_AND_ASSIGN(SpdyDataIR);
487 };
488 
489 class NET_EXPORT_PRIVATE SpdySynStreamIR
490     : public SpdyFrameWithNameValueBlockIR {
491  public:
SpdySynStreamIR(SpdyStreamId stream_id)492   explicit SpdySynStreamIR(SpdyStreamId stream_id)
493       : SpdyFrameWithNameValueBlockIR(stream_id),
494         associated_to_stream_id_(0),
495         priority_(0),
496         slot_(0),
497         unidirectional_(false) {}
associated_to_stream_id()498   SpdyStreamId associated_to_stream_id() const {
499     return associated_to_stream_id_;
500   }
set_associated_to_stream_id(SpdyStreamId stream_id)501   void set_associated_to_stream_id(SpdyStreamId stream_id) {
502     associated_to_stream_id_ = stream_id;
503   }
priority()504   SpdyPriority priority() const { return priority_; }
set_priority(SpdyPriority priority)505   void set_priority(SpdyPriority priority) { priority_ = priority; }
slot()506   SpdyCredentialSlot slot() const { return slot_; }
set_slot(SpdyCredentialSlot slot)507   void set_slot(SpdyCredentialSlot slot) { slot_ = slot; }
unidirectional()508   bool unidirectional() const { return unidirectional_; }
set_unidirectional(bool unidirectional)509   void set_unidirectional(bool unidirectional) {
510     unidirectional_ = unidirectional;
511   }
512 
513   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
514 
515  private:
516   SpdyStreamId associated_to_stream_id_;
517   SpdyPriority priority_;
518   SpdyCredentialSlot slot_;
519   bool unidirectional_;
520 
521   DISALLOW_COPY_AND_ASSIGN(SpdySynStreamIR);
522 };
523 
524 class SpdySynReplyIR : public SpdyFrameWithNameValueBlockIR {
525  public:
SpdySynReplyIR(SpdyStreamId stream_id)526   explicit SpdySynReplyIR(SpdyStreamId stream_id)
527       : SpdyFrameWithNameValueBlockIR(stream_id) {}
528 
529   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
530 
531  private:
532   DISALLOW_COPY_AND_ASSIGN(SpdySynReplyIR);
533 };
534 
535 class SpdyRstStreamIR : public SpdyFrameWithStreamIdIR {
536  public:
SpdyRstStreamIR(SpdyStreamId stream_id,SpdyRstStreamStatus status)537   SpdyRstStreamIR(SpdyStreamId stream_id, SpdyRstStreamStatus status)
538       : SpdyFrameWithStreamIdIR(stream_id) {
539     set_status(status);
540   }
status()541   SpdyRstStreamStatus status() const {
542     return status_;
543   }
set_status(SpdyRstStreamStatus status)544   void set_status(SpdyRstStreamStatus status) {
545     DCHECK_NE(status, RST_STREAM_INVALID);
546     DCHECK_LT(status, RST_STREAM_NUM_STATUS_CODES);
547     status_ = status;
548   }
549 
550   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
551 
552  private:
553   SpdyRstStreamStatus status_;
554 
555   DISALLOW_COPY_AND_ASSIGN(SpdyRstStreamIR);
556 };
557 
558 class SpdySettingsIR : public SpdyFrameIR {
559  public:
560   // Associates flags with a value.
561   struct Value {
ValueValue562     Value() : persist_value(false),
563               persisted(false),
564               value(0) {}
565     bool persist_value;
566     bool persisted;
567     int32 value;
568   };
569   typedef std::map<SpdySettingsIds, Value> ValueMap;
570 
571   SpdySettingsIR();
572 
573   virtual ~SpdySettingsIR();
574 
575   // Overwrites as appropriate.
values()576   const ValueMap& values() const { return values_; }
AddSetting(SpdySettingsIds id,bool persist_value,bool persisted,int32 value)577   void AddSetting(SpdySettingsIds id,
578                   bool persist_value,
579                   bool persisted,
580                   int32 value) {
581     // TODO(hkhalil): DCHECK_LE(SETTINGS_UPLOAD_BANDWIDTH, id);
582     // TODO(hkhalil): DCHECK_GE(SETTINGS_INITIAL_WINDOW_SIZE, id);
583     values_[id].persist_value = persist_value;
584     values_[id].persisted = persisted;
585     values_[id].value = value;
586   }
clear_settings()587   bool clear_settings() const { return clear_settings_; }
set_clear_settings(bool clear_settings)588   void set_clear_settings(bool clear_settings) {
589     clear_settings_ = clear_settings;
590   }
591 
592   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
593 
594  private:
595   ValueMap values_;
596   bool clear_settings_;
597 
598   DISALLOW_COPY_AND_ASSIGN(SpdySettingsIR);
599 };
600 
601 class SpdyPingIR : public SpdyFrameIR {
602  public:
SpdyPingIR(SpdyPingId id)603   explicit SpdyPingIR(SpdyPingId id) : id_(id) {}
id()604   SpdyPingId id() const { return id_; }
605 
606   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
607 
608  private:
609   SpdyPingId id_;
610 
611   DISALLOW_COPY_AND_ASSIGN(SpdyPingIR);
612 };
613 
614 class SpdyGoAwayIR : public SpdyFrameIR {
615  public:
SpdyGoAwayIR(SpdyStreamId last_good_stream_id,SpdyGoAwayStatus status)616   SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyGoAwayStatus status) {
617     set_last_good_stream_id(last_good_stream_id);
618     set_status(status);
619   }
last_good_stream_id()620   SpdyStreamId last_good_stream_id() const { return last_good_stream_id_; }
set_last_good_stream_id(SpdyStreamId last_good_stream_id)621   void set_last_good_stream_id(SpdyStreamId last_good_stream_id) {
622     DCHECK_LE(0u, last_good_stream_id);
623     DCHECK_EQ(0u, last_good_stream_id & ~kStreamIdMask);
624     last_good_stream_id_ = last_good_stream_id;
625   }
status()626   SpdyGoAwayStatus status() const { return status_; }
set_status(SpdyGoAwayStatus status)627   void set_status(SpdyGoAwayStatus status) {
628     // TODO(hkhalil): Check valid ranges of status?
629     status_ = status;
630   }
631 
632   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
633 
634  private:
635   SpdyStreamId last_good_stream_id_;
636   SpdyGoAwayStatus status_;
637 
638   DISALLOW_COPY_AND_ASSIGN(SpdyGoAwayIR);
639 };
640 
641 class SpdyHeadersIR : public SpdyFrameWithNameValueBlockIR {
642  public:
SpdyHeadersIR(SpdyStreamId stream_id)643   explicit SpdyHeadersIR(SpdyStreamId stream_id)
644       : SpdyFrameWithNameValueBlockIR(stream_id) {}
645 
646   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
647 
648  private:
649   DISALLOW_COPY_AND_ASSIGN(SpdyHeadersIR);
650 };
651 
652 class SpdyWindowUpdateIR : public SpdyFrameWithStreamIdIR {
653  public:
SpdyWindowUpdateIR(SpdyStreamId stream_id,int32 delta)654   SpdyWindowUpdateIR(SpdyStreamId stream_id, int32 delta)
655       : SpdyFrameWithStreamIdIR(stream_id) {
656     set_delta(delta);
657   }
delta()658   int32 delta() const { return delta_; }
set_delta(int32 delta)659   void set_delta(int32 delta) {
660     DCHECK_LT(0, delta);
661     DCHECK_LE(delta, kSpdyMaximumWindowSize);
662     delta_ = delta;
663   }
664 
665   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
666 
667  private:
668   int32 delta_;
669 
670   DISALLOW_COPY_AND_ASSIGN(SpdyWindowUpdateIR);
671 };
672 
673 class SpdyCredentialIR : public SpdyFrameIR {
674  public:
675   typedef std::vector<std::string> CertificateList;
676 
677   explicit SpdyCredentialIR(int16 slot);
678   virtual ~SpdyCredentialIR();
679 
slot()680   int16 slot() const { return slot_; }
set_slot(int16 slot)681   void set_slot(int16 slot) {
682     // TODO(hkhalil): Verify valid slot range?
683     slot_ = slot;
684   }
proof()685   base::StringPiece proof() const { return proof_; }
set_proof(const base::StringPiece & proof)686   void set_proof(const base::StringPiece& proof) {
687     proof.CopyToString(&proof_);
688   }
certificates()689   const CertificateList* certificates() const { return &certificates_; }
AddCertificate(const base::StringPiece & certificate)690   void AddCertificate(const base::StringPiece& certificate) {
691     certificates_.push_back(certificate.as_string());
692   }
693 
694   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
695 
696  private:
697   int16 slot_;
698   std::string proof_;
699   CertificateList certificates_;
700 
701   DISALLOW_COPY_AND_ASSIGN(SpdyCredentialIR);
702 };
703 
704 class NET_EXPORT_PRIVATE SpdyBlockedIR
NON_EXPORTED_BASE(SpdyFrameWithStreamIdIR)705     : public NON_EXPORTED_BASE(SpdyFrameWithStreamIdIR) {
706   public:
707    explicit SpdyBlockedIR(SpdyStreamId stream_id)
708        : SpdyFrameWithStreamIdIR(stream_id) {}
709 
710   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
711 
712   private:
713    DISALLOW_COPY_AND_ASSIGN(SpdyBlockedIR);
714 };
715 
716 class SpdyPushPromiseIR : public SpdyFrameWithNameValueBlockIR {
717  public:
SpdyPushPromiseIR(SpdyStreamId stream_id,SpdyStreamId promised_stream_id)718   SpdyPushPromiseIR(SpdyStreamId stream_id, SpdyStreamId promised_stream_id)
719       : SpdyFrameWithNameValueBlockIR(stream_id),
720         promised_stream_id_(promised_stream_id) {}
promised_stream_id()721   SpdyStreamId promised_stream_id() const { return promised_stream_id_; }
set_promised_stream_id(SpdyStreamId id)722   void set_promised_stream_id(SpdyStreamId id) { promised_stream_id_ = id; }
723 
724   virtual void Visit(SpdyFrameVisitor* visitor) const OVERRIDE;
725 
726  private:
727   SpdyStreamId promised_stream_id_;
728   DISALLOW_COPY_AND_ASSIGN(SpdyPushPromiseIR);
729 };
730 
731 
732 // -------------------------------------------------------------------------
733 // Wrapper classes for various SPDY frames.
734 
735 // All Spdy Frame types derive from this SpdyFrame class.
736 class SpdyFrame {
737  public:
738   // Create a SpdyFrame using a pre-created buffer.
739   // If |owns_buffer| is true, this class takes ownership of the buffer
740   // and will delete it on cleanup.  The buffer must have been created using
741   // new char[].
742   // If |owns_buffer| is false, the caller retains ownership of the buffer and
743   // is responsible for making sure the buffer outlives this frame.  In other
744   // words, this class does NOT create a copy of the buffer.
SpdyFrame(char * data,size_t size,bool owns_buffer)745   SpdyFrame(char* data, size_t size, bool owns_buffer)
746       : frame_(data),
747         size_(size),
748         owns_buffer_(owns_buffer) {
749     DCHECK(frame_);
750   }
751 
~SpdyFrame()752   ~SpdyFrame() {
753     if (owns_buffer_) {
754       delete [] frame_;
755     }
756     frame_ = NULL;
757   }
758 
759   // Provides access to the frame bytes, which is a buffer containing
760   // the frame packed as expected for sending over the wire.
data()761   char* data() const { return frame_; }
762 
763   // Returns the actual size of the underlying buffer.
size()764   size_t size() const { return size_; }
765 
766  protected:
767   char* frame_;
768 
769  private:
770   size_t size_;
771   bool owns_buffer_;
772   DISALLOW_COPY_AND_ASSIGN(SpdyFrame);
773 };
774 
775 // This interface is for classes that want to process SpdyFrameIRs without
776 // having to know what type they are.  An instance of this interface can be
777 // passed to a SpdyFrameIR's Visit method, and the appropriate type-specific
778 // method of this class will be called.
779 class SpdyFrameVisitor {
780  public:
781   virtual void VisitSynStream(const SpdySynStreamIR& syn_stream) = 0;
782   virtual void VisitSynReply(const SpdySynReplyIR& syn_reply) = 0;
783   virtual void VisitRstStream(const SpdyRstStreamIR& rst_stream) = 0;
784   virtual void VisitSettings(const SpdySettingsIR& settings) = 0;
785   virtual void VisitPing(const SpdyPingIR& ping) = 0;
786   virtual void VisitGoAway(const SpdyGoAwayIR& goaway) = 0;
787   virtual void VisitHeaders(const SpdyHeadersIR& headers) = 0;
788   virtual void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) = 0;
789   virtual void VisitCredential(const SpdyCredentialIR& credential) = 0;
790   virtual void VisitBlocked(const SpdyBlockedIR& blocked) = 0;
791   virtual void VisitPushPromise(const SpdyPushPromiseIR& push_promise) = 0;
792   virtual void VisitData(const SpdyDataIR& data) = 0;
793 
794  protected:
SpdyFrameVisitor()795   SpdyFrameVisitor() {}
~SpdyFrameVisitor()796   virtual ~SpdyFrameVisitor() {}
797 
798  private:
799   DISALLOW_COPY_AND_ASSIGN(SpdyFrameVisitor);
800 };
801 
802 }  // namespace net
803 
804 #endif  // NET_SPDY_SPDY_PROTOCOL_H_
805