proxygen
SPDYCodecTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
19 #include <random>
20 
21 using namespace folly;
22 using namespace proxygen;
23 using namespace std;
24 using namespace testing;
25 
26 size_t parseSPDY(SPDYCodec* codec, const uint8_t* inputData, uint32_t length,
27  int32_t atOnce, FakeHTTPCodecCallback& callbacks) {
28  codec->setCallback(&callbacks);
29  return parse(codec, inputData, length, atOnce, callbacks.getStopFn());
30 }
31 
33 { 0x80, 0x03, 0x00, 0x01,
34  0x01, 0x00, 0x00, 0x04, // length must be >= 12
35  0x61, 0x62, 0x63, 0x64
36 };
37 
38 TEST(SPDYCodecTest, SPDYVersionSettingsCommonHeaderNameCheck) {
39  // The purpose of this test is to ensure that should the below header names
40  // become part of the common set, it fails indicating that the SPDYCodec
41  // needs updating in those places that create compress/Header objects using
42  // the failed name.
43  EXPECT_EQ(HTTPCommonHeaders::hash(spdy::kNameVersionv3), HTTP_HEADER_OTHER);
44  EXPECT_EQ(HTTPCommonHeaders::hash(spdy::kNameHostv3), HTTP_HEADER_OTHER);
45  // The follow verifies assumptions that should never change regarding the
46  // mapping of specific SPDY3 constants to common headers. Should they fail,
47  // the SPDYCodec would require updating in the places in which they are used
48  // in creating compress/Header objects.
49  EXPECT_EQ(HTTPCommonHeaders::hash(
51  EXPECT_EQ(HTTPCommonHeaders::hash(
53  EXPECT_EQ(HTTPCommonHeaders::hash(
55  EXPECT_EQ(HTTPCommonHeaders::hash(
57 }
58 
59 TEST(SPDYCodecTest, JunkSPDY) {
60  SPDYCodec codec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3);
61  FakeHTTPCodecCallback callbacks;
62  size_t unconsumed =
63  parseSPDY(&codec, shortSynStream, sizeof(shortSynStream), -1, callbacks);
64  EXPECT_EQ(unconsumed, 0);
65  EXPECT_EQ(callbacks.sessionErrors, 1);
66  EXPECT_EQ(callbacks.streamErrors, 0);
67 }
68 
70 { 0x80, 0x03, 0x00, 0x06,
71  0x00, 0x00, 0x00, 0x05,
72  0x00, 0x00, 0x00, 0x00,
73  0x00
74 };
75 
76 TEST(SPDYCodecTest, LongPing) {
77  SPDYCodec codec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3);
78  FakeHTTPCodecCallback callbacks;
79  size_t unconsumed =
80  parseSPDY(&codec, longPing, sizeof(longPing), -1, callbacks);
81  EXPECT_EQ(unconsumed, 0);
82  EXPECT_EQ(callbacks.sessionErrors, 1);
83  EXPECT_EQ(callbacks.streamErrors, 0);
84 }
85 
87 { 0x80, 0x03, 0x00, 0x0A,
88  0x00, 0x00, 0x00, 0x05,
89  0x00, 0x00, 0x00, 0x00,
90  0x00
91 };
92 
93 TEST(SPDYCodecTest, BadType) {
94  // If an endpoint receives a control frame for a type it does not recognize,
95  // it must ignore the frame.
96  SPDYCodec codec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3);
97  FakeHTTPCodecCallback callbacks;
98  size_t unconsumed =
99  parseSPDY(&codec, badType, sizeof(badType), -1, callbacks);
100  EXPECT_EQ(unconsumed, 0);
101  EXPECT_EQ(callbacks.sessionErrors, 0);
102  EXPECT_EQ(callbacks.streamErrors, 0);
103 }
104 
109 {
110 0x80, 0x03, 0x00, 0x01, 0x01, 0x00, 0x04, 0x1a,
111 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
112 0x00, 0x00, 0x38, 0xea, 0xe3, 0xc6, 0xa7, 0xc2,
113 0x02, 0x65, 0x57, 0x50, 0x22, 0xb4, 0xc2, 0x9e,
114 0x20, 0xd9, 0xad, 0x10, 0xa9, 0xd9, 0xdd, 0x35,
115 0x04, 0x94, 0xf1, 0xac, 0xa0, 0x45, 0x87, 0x14,
116 0x30, 0xed, 0xeb, 0x25, 0xa6, 0x15, 0x65, 0xe6,
117 0xa5, 0xe8, 0x15, 0x27, 0xe9, 0xa5, 0x01, 0x8b,
118 0xe9, 0x24, 0x60, 0x42, 0xd5, 0x4b, 0x06, 0x17,
119 0x30, 0xec, 0x56, 0xc5, 0xc0, 0xa2, 0x33, 0x17,
120 0x5c, 0xbe, 0x66, 0x94, 0x94, 0x14, 0x14, 0x83,
121 0xb5, 0x16, 0x24, 0x82, 0x8b, 0x3b, 0x6e, 0x80,
122 0x00, 0xd2, 0x2f, 0x2e, 0x49, 0x2c, 0x29, 0x2d,
123 0xd6, 0x2b, 0xc8, 0x28, 0x00, 0x08, 0x20, 0x94,
124 0x22, 0x80, 0x03, 0x20, 0x80, 0xf2, 0xf2, 0x75,
125 0x93, 0x13, 0x93, 0x33, 0x52, 0x01, 0x02, 0x08,
126 0x5b, 0xe1, 0xcb, 0x01, 0x10, 0x40, 0x79, 0xf9,
127 0xba, 0xc9, 0x89, 0xc9, 0x19, 0xa9, 0x00, 0x01,
128 0x84, 0x52, 0x1b, 0x78, 0x21, 0x42, 0x1f, 0x7b,
129 0x78, 0xa2, 0x85, 0xba, 0x35, 0xc8, 0xd7, 0x96,
130 0xd0, 0x58, 0x29, 0x4f, 0x4d, 0x2a, 0xd0, 0xd1,
131 0xd2, 0xd7, 0x02, 0x0b, 0x5a, 0x00, 0x4d, 0x93,
132 0x84, 0x96, 0x01, 0xba, 0x99, 0x79, 0xc5, 0xa9,
133 0xc9, 0xa5, 0x45, 0xa9, 0xba, 0x45, 0x90, 0x84,
134 0x0b, 0x72, 0x3f, 0x23, 0x40, 0x00, 0x19, 0x02,
135 0x04, 0x10, 0x46, 0xd1, 0x50, 0xee, 0x9b, 0x5f,
136 0x95, 0x99, 0x93, 0x93, 0xa8, 0x6f, 0xaa, 0x67,
137 0xa0, 0xa0, 0xe1, 0x9b, 0x98, 0x9c, 0x99, 0x57,
138 0x92, 0x5f, 0x9c, 0x61, 0x0d, 0x4e, 0xba, 0x39,
139 0xc0, 0x14, 0x97, 0xac, 0xe0, 0x1f, 0xac, 0x10,
140 0xa1, 0x60, 0x68, 0x10, 0x0f, 0x44, 0xa6, 0x9a,
141 0xc0, 0x74, 0x08, 0x4c, 0xb5, 0xe1, 0xa9, 0x49,
142 0xde, 0x99, 0x25, 0xfa, 0xa6, 0xc6, 0xe6, 0x7a,
143 0xc6, 0x66, 0x0a, 0x1a, 0xde, 0x1e, 0x21, 0xbe,
144 0x3e, 0x3a, 0x0a, 0x39, 0x99, 0xd9, 0xa9, 0x0a,
145 0xee, 0xa9, 0xc9, 0xd9, 0xf9, 0x9a, 0x0a, 0xce,
146 0x19, 0xc0, 0x72, 0x3a, 0x55, 0xdf, 0xc4, 0x42,
147 0xcf, 0x40, 0xcf, 0xc8, 0xd4, 0x18, 0x64, 0x7a,
148 0x70, 0x62, 0x5a, 0x62, 0x51, 0x26, 0x54, 0x13,
149 0xf6, 0x4a, 0x4f, 0x18, 0x9c, 0x16, 0x14, 0x60,
150 0x89, 0x41, 0x01, 0x94, 0x1a, 0x90, 0x54, 0x22,
151 0x57, 0x41, 0xa9, 0x79, 0xba, 0xa1, 0xc1, 0xc0,
152 0x34, 0x00, 0xf7, 0x39, 0x1b, 0xac, 0x94, 0x61,
153 0x7a, 0x0c, 0x10, 0x40, 0xb9, 0xf1, 0x25, 0xc5,
154 0xb6, 0x86, 0x26, 0x86, 0x66, 0x96, 0xa6, 0x86,
155 0xe6, 0x06, 0x66, 0xd6, 0x00, 0x01, 0xa4, 0x90,
156 0x92, 0x58, 0x52, 0x64, 0xeb, 0x1b, 0x5f, 0x60,
157 0x10, 0xe6, 0x58, 0x92, 0x15, 0x6e, 0xe9, 0x92,
158 0x57, 0x61, 0xe9, 0x1b, 0x16, 0xe8, 0xe9, 0x13,
159 0xef, 0x98, 0x9d, 0x66, 0x69, 0x0d, 0x10, 0x40,
160 0x0a, 0xf1, 0xe9, 0x89, 0xb6, 0xee, 0x8e, 0x86,
161 0x7a, 0x46, 0x7a, 0x86, 0x46, 0x46, 0x86, 0xe6,
162 0x66, 0x66, 0x16, 0x66, 0x96, 0x7a, 0x86, 0x26,
163 0xc6, 0xc6, 0xe6, 0x96, 0xc6, 0x26, 0x26, 0x26,
164 0xd6, 0x00, 0x01, 0xa4, 0x90, 0x53, 0x6a, 0x1b,
165 0x92, 0xee, 0x53, 0x18, 0x5a, 0xe2, 0x63, 0xee,
166 0xe5, 0x9a, 0xa9, 0xeb, 0xef, 0x5e, 0x98, 0x96,
167 0x14, 0x98, 0xeb, 0xe1, 0x5d, 0x9a, 0x51, 0x6e,
168 0x0d, 0x10, 0x40, 0x0a, 0x15, 0x25, 0x45, 0x79,
169 0xb6, 0x8e, 0x21, 0xa6, 0xc1, 0xc6, 0xc5, 0xba,
170 0x61, 0xa6, 0x7e, 0x49, 0xa5, 0x65, 0x51, 0xa1,
171 0xce, 0x29, 0xc9, 0x8e, 0xd6, 0x00, 0x01, 0x08,
172 0x82, 0x43, 0x23, 0x86, 0x61, 0x20, 0x00, 0x82,
173 0xad, 0x84, 0x1c, 0xf4, 0x8c, 0xfe, 0x5e, 0x8a,
174 0x51, 0x80, 0xa2, 0x4a, 0x6c, 0x68, 0x31, 0xcb,
175 0x24, 0xdd, 0x67, 0xf7, 0x75, 0x44, 0xfc, 0x3e,
176 0xec, 0x5f, 0x74, 0xdd, 0x28, 0xd9, 0x0b, 0x0e,
177 0x74, 0xdd, 0xdb, 0xb3, 0x50, 0xb2, 0x47, 0x8d,
178 0xac, 0x91, 0xb5, 0xb4, 0x30, 0x71, 0xa0, 0xd7,
179 0x44, 0xc9, 0x5e, 0x70, 0xa0, 0xd7, 0xdc, 0x9e,
180 0x85, 0x92, 0x3d, 0x6a, 0xd5, 0xb6, 0xe7, 0xbb,
181 0x94, 0xda, 0x70, 0xa0, 0xf3, 0x44, 0xc9, 0x1e,
182 0x38, 0xd0, 0x79, 0x6e, 0xcf, 0x42, 0xc9, 0x3f,
183 0x41, 0x70, 0x8e, 0x03, 0x20, 0x08, 0x00, 0x01,
184 0xf0, 0x35, 0x5b, 0x9a, 0xb0, 0x07, 0x51, 0x62,
185 0x45, 0xf0, 0x27, 0x34, 0x34, 0x54, 0xfa, 0xff,
186 0x38, 0xd3, 0x99, 0xc4, 0xbe, 0x6a, 0xd8, 0xdc,
187 0xa0, 0x01, 0x69, 0xcd, 0x0d, 0x09, 0xee, 0x05,
188 0x1a, 0x90, 0xd6, 0xdc, 0xc7, 0xf7, 0x42, 0x82,
189 0x3b, 0x43, 0x87, 0x4e, 0xa9, 0x94, 0x71, 0x3e,
190 0xf7, 0x2f, 0x80, 0x14, 0x0a, 0x6c, 0x75, 0x8d,
191 0xac, 0x01, 0x02, 0x48, 0x21, 0xb9, 0x38, 0xd7,
192 0xd6, 0xc8, 0x1a, 0x20, 0x80, 0x14, 0x2a, 0x8a,
193 0x6d, 0x4d, 0x8c, 0x54, 0x8d, 0x1d, 0xb3, 0x8a,
194 0x2c, 0x13, 0x53, 0x7d, 0xb3, 0x2c, 0x3c, 0x75,
195 0x83, 0x93, 0x0b, 0x03, 0x55, 0x8d, 0x1d, 0x8d,
196 0x54, 0x8d, 0x1d, 0x0d, 0x4d, 0x0c, 0x2c, 0x4c,
197 0xcd, 0x2c, 0x4c, 0xcc, 0x0d, 0x55, 0x8d, 0x1d,
198 0x4d, 0x0d, 0x8d, 0x8c, 0xad, 0x01, 0x02, 0x48,
199 0xa1, 0xd8, 0xd6, 0x31, 0xd1, 0xc4, 0xa8, 0xa4,
200 0x28, 0xa2, 0xd2, 0xdd, 0x33, 0xb0, 0x3c, 0xaa,
201 0x2c, 0xd0, 0xdf, 0x3b, 0xbc, 0x5c, 0xcf, 0x29,
202 0xc4, 0x32, 0xb0, 0x32, 0xc2, 0x1a, 0x20, 0x80,
203 0x14, 0xd2, 0x8a, 0x6c, 0x0d, 0x4c, 0xfc, 0x3c,
204 0x93, 0x7c, 0x9c, 0x0a, 0x9d, 0x42, 0x83, 0x53,
205 0xbc, 0x7d, 0xfc, 0x32, 0x83, 0xf5, 0x1c, 0xc3,
206 0x23, 0xfc, 0x33, 0xf3, 0x92, 0x53, 0x33, 0x0c,
207 0x82, 0xcd, 0x4a, 0x3d, 0x92, 0x8b, 0x83, 0x53,
208 0x12, 0x43, 0xe2, 0xbd, 0x4d, 0xe3, 0x33, 0xdd,
209 0xb3, 0xf5, 0x9c, 0x82, 0x8b, 0x4c, 0x72, 0x13,
210 0xf5, 0x5c, 0x0b, 0xf5, 0xdc, 0x22, 0x73, 0xf5,
211 0x0c, 0xf4, 0x1c, 0xc3, 0x43, 0xbd, 0x22, 0x1d,
212 0x5d, 0x52, 0xac, 0x01, 0x02, 0x48, 0x21, 0x39,
213 0xbe, 0xb4, 0x38, 0xb5, 0xc8, 0xd6, 0xd4, 0xc2,
214 0xc0, 0xd4, 0xdc, 0xd4, 0xcc, 0xd0, 0xd0, 0x1a,
215 0x20, 0x80, 0x14, 0x12, 0x93, 0x4b, 0x6c, 0x0d,
216 0x4d, 0x4c, 0x4c, 0x8d, 0x2d, 0x4c, 0x0d, 0x4d,
217 0xcc, 0xcc, 0x0d, 0x2c, 0x54, 0x8d, 0xdc, 0x4c,
218 0xac, 0x01, 0x02, 0x10, 0x04, 0x07, 0x37, 0x08,
219 0xc3, 0x30, 0x00, 0x00, 0x57, 0x61, 0x84, 0xd8,
220 0xb1, 0xc1, 0x79, 0xf0, 0xa8, 0x54, 0x7b, 0x8d,
221 0x8a, 0x16, 0x3f, 0x90, 0xd2, 0x08, 0x25, 0x0e,
222 0x5d, 0x9f, 0xbb, 0xdb, 0xb7, 0xfb, 0xf0, 0x76,
223 0xf8, 0x53, 0xd7, 0x9f, 0x65, 0x8d, 0xcf, 0xe9,
224 0x06, 0x44, 0x9c, 0x85, 0x11, 0x8b, 0xce, 0xe1,
225 0xdd, 0x16, 0x64, 0x49, 0xfc, 0xe0, 0x3b, 0xc0,
226 0x82, 0x3a, 0xe2, 0x15, 0x6e, 0xeb, 0xd8, 0xd1,
227 0x80, 0x88, 0xb3, 0x50, 0x4a, 0x52, 0x72, 0xd1,
228 0x40, 0xdb, 0x78, 0xdf, 0xf8, 0xad, 0xf5, 0x44,
229 0x6b, 0xb3, 0x56, 0x9d, 0x47, 0xa0, 0x01, 0x11,
230 0x67, 0xa1, 0x94, 0xa4, 0x10, 0x68, 0x74, 0x6b,
231 0xb3, 0x56, 0x8d, 0xcb, 0x00, 0xff, 0x04, 0xc1,
232 0x41, 0x0e, 0x80, 0x30, 0x08, 0x04, 0xc0, 0x2f,
233 0x95, 0xc2, 0x42, 0x37, 0x1e, 0xb1, 0xf4, 0x19,
234 0xc6, 0x98, 0x18, 0x8f, 0x1e, 0xfc, 0x7f, 0x9c,
235 0xa1, 0x36, 0xd0, 0xdd, 0xe7, 0xf9, 0x95, 0x98,
236 0x41, 0x87, 0x19, 0xe9, 0x9d, 0xcb, 0x0c, 0x3a,
237 0xd0, 0x3b, 0x23, 0x34, 0xe7, 0xf5, 0xd4, 0xfe,
238 0x1e, 0xb8, 0x31, 0x1a, 0x02, 0x2e, 0x52, 0x02,
239 0x32, 0x73, 0xfb, 0x05, 0x90, 0x42, 0x79, 0x8a,
240 0xad, 0x91, 0x85, 0x89, 0x49, 0x85, 0xa1, 0xa9,
241 0xa9, 0x05, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00,
242 0xff, 0xff,
243 };
244 
245 TEST(SPDYCodecTest, SynStreamBoundaries) {
246  for (int i = -1; i < int(sizeof(synStream)); i++) {
247  SPDYCodec codec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3_1);
248  FakeHTTPCodecCallback callbacks;
249  size_t unconsumed =
250  parseSPDY(&codec, synStream, sizeof(synStream), i, callbacks);
251  EXPECT_EQ(unconsumed, 0);
252  EXPECT_EQ(callbacks.messageBegin, 1);
253  EXPECT_EQ(callbacks.headersComplete, 1);
254  EXPECT_EQ(callbacks.messageComplete, 1);
255  EXPECT_EQ(callbacks.streamErrors, 0);
256  EXPECT_EQ(callbacks.sessionErrors, 0);
257  }
258 }
259 
260 TEST(SPDYCodecTest, SetSettings) {
261  SPDYCodec codec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3);
263  // There are 2 settings by default. Turn on another setting
264  settings->setSetting(SettingsId::_SPDY_DOWNLOAD_BANDWIDTH, 10);
265  // This should no-op since this setting should be off by default
266  settings->unsetSetting(SettingsId::_SPDY_ROUND_TRIP_TIME);
267  EXPECT_EQ(settings->getSetting(SettingsId::_SPDY_ROUND_TRIP_TIME), nullptr);
268  EXPECT_EQ(settings->getSetting(SettingsId::_SPDY_CURRENT_CWND), nullptr);
269  EXPECT_EQ(settings->getSetting(SettingsId::MAX_CONCURRENT_STREAMS)->value,
271  EXPECT_EQ(settings->getSetting(SettingsId::INITIAL_WINDOW_SIZE)->value,
273  EXPECT_EQ(
274  settings->getSetting(SettingsId::_SPDY_DOWNLOAD_BANDWIDTH)->value, 10);
275  // Turn off one of the defaults
276  settings->unsetSetting(SettingsId::MAX_CONCURRENT_STREAMS);
277  // Change the value of an existing default setting
278  settings->setSetting(SettingsId::INITIAL_WINDOW_SIZE, 123);
279  EXPECT_EQ(settings->getSetting(SettingsId::MAX_CONCURRENT_STREAMS),
280  nullptr);
281  EXPECT_EQ(settings->getSetting(SettingsId::INITIAL_WINDOW_SIZE)->value,
282  123);
283  EXPECT_EQ(settings->getNumSettings(), 2);
284  // Change the value of a unset setting
285  settings->setSetting(SettingsId::MAX_CONCURRENT_STREAMS, 400);
286  EXPECT_EQ(settings->getSetting(SettingsId::MAX_CONCURRENT_STREAMS)->value,
287  400);
288  EXPECT_EQ(settings->getNumSettings(), 3);
289 }
290 
291 TEST(SPDYCodecTest, FrameTooLarge) {
292  SPDYCodec codec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3_1);
293  codec.setMaxFrameLength(500);
294  FakeHTTPCodecCallback callbacks;
295  size_t unconsumed = parseSPDY(&codec, synStream, sizeof(synStream), -1,
296  callbacks);
297  EXPECT_EQ(unconsumed, 0);
298  EXPECT_EQ(callbacks.sessionErrors, 1);
299  EXPECT_EQ(callbacks.streamErrors, 1);
300 }
301 
302 TEST(SPDYCodecTest, FrameUncompressedTooLarge) {
303  SPDYCodec codec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3_1);
304  codec.setMaxUncompressedHeaders(600);
305  FakeHTTPCodecCallback callbacks;
306  size_t unconsumed = parseSPDY(&codec, synStream, sizeof(synStream), -1,
307  callbacks);
308  EXPECT_EQ(unconsumed, 0);
309  EXPECT_EQ(callbacks.sessionErrors, 1);
310  EXPECT_EQ(callbacks.streamErrors, 1);
311 }
312 
314 { 0x80, 0x03, 0x00, 0x0B, // ctl frame for spdy/3 (11 is not defined)
315  0x00, 0x00, 0x00, 0x02, // len = 2
316  0xD4, 0x74 // The data
317 };
318 
319 TEST(SPDYCodecTest, UnsupportedVersion) {
320  // Send a spdy/2 frame on a spdy/3 codec
321  SPDYCodec codec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3);
322  FakeHTTPCodecCallback callbacks;
323  size_t unconsumed = parseSPDY(&codec, shortSynStream,
324  sizeof(shortSynStream), -1, callbacks);
325  EXPECT_EQ(unconsumed, 0);
326  // Expect a GOAWAY with PROTOCOL_ERROR (because of unsupported version)
327  EXPECT_EQ(callbacks.sessionErrors, 1);
328  EXPECT_EQ(callbacks.streamErrors, 0);
329  EXPECT_EQ(callbacks.lastParseError->getCodecStatusCode(),
331 }
332 
333 TEST(SPDYCodecTest, UnsupportedFrameType) {
334  SPDYCodec codec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3);
335  FakeHTTPCodecCallback callbacks;
336  size_t unconsumed = parseSPDY(&codec, spdy3UnknownCtlFrame,
337  sizeof(spdy3UnknownCtlFrame), -1, callbacks);
338  EXPECT_EQ(unconsumed, 0);
339  EXPECT_EQ(callbacks.sessionErrors, 0);
340  EXPECT_EQ(callbacks.streamErrors, 0);
341  // Spec says unknown control frames must be ignored
342 }
343 
344 template <typename Codec>
345 unique_ptr<folly::IOBuf> getSynStream(
346  Codec& egressCodec,
348  const HTTPMessage& msg,
349  uint32_t assocStreamId = SPDYCodec::NoStream,
350  bool eom = false,
351  HTTPHeaderSize* size = nullptr) {
353  if (assocStreamId == SPDYCodec::NoStream) {
354  egressCodec.generateHeader(output, streamID, msg, eom, size);
355  } else {
356  egressCodec.generatePushPromise(output, streamID, msg, assocStreamId, eom,
357  size);
358  }
359  return output.move();
360 }
361 
362 template <typename Codec>
363 unique_ptr<folly::IOBuf> getSynStream(Codec& egressCodec,
364  uint32_t streamID) {
365  HTTPMessage msg;
366  msg.setMethod("GET");
367  msg.getHeaders().set("HOST", "www.foo.com");
368  msg.setURL("https://www.foo.com");
369  return getSynStream(egressCodec, streamID, msg);
370 }
371 
372 // Runs the function with all combinations of spdy/2 and spdy/3
373 template <typename Codec, typename F, typename V>
374 void callFunction(F f, V version) {
375  Codec ingressCodec(TransportDirection::DOWNSTREAM, version);
376  Codec egressCodec(TransportDirection::UPSTREAM, version);
377  f(ingressCodec, egressCodec);
378 }
379 
380 #define copyForMe(F, C, V) callFunction<C>(F<C, C>, \
381  SPDYVersion::V)
382 
383 #define permuteTest(f) copyForMe(f, SPDYCodec, SPDY3); \
384  copyForMe(f, SPDYCodec, SPDY3_1);
385 
389 unique_ptr<folly::IOBuf> getVersionedSpdyFrame(const uint8_t* bytes,
390  size_t len,
391  uint8_t version) {
392  auto frame = folly::IOBuf::copyBuffer(bytes, len);
393  uint8_t* data = frame->writableData();
394  data[1] = version; /* Set the version */
395  return frame;
396 }
397 
398 template <typename Codec1, typename Codec2>
399 void maxTransactionHelper(Codec1& ingressCodec, Codec2& egressCodec,
400  uint32_t parallel) {
401  uint16_t expectedFailures = 0;
402  uint16_t synCount = 101;
403  ingressCodec.getEgressSettings()->setSetting(
404  SettingsId::MAX_CONCURRENT_STREAMS, parallel);
405  FakeHTTPCodecCallback callbacks;
406  ingressCodec.setCallback(&callbacks);
407  for (uint16_t i = 0; i < synCount; ++i) {
408  if (i >= parallel) {
409  ++expectedFailures;
410  }
411  auto toParse = getSynStream(egressCodec, 2*i + 1);
412  ingressCodec.onIngress(*toParse);
413  EXPECT_EQ(callbacks.sessionErrors, 0);
414  EXPECT_EQ(callbacks.streamErrors, expectedFailures);
415  }
416 }
417 
418 template <typename Codec1, typename Codec2>
419 void doDefaultMaxTransactionTest(Codec1& ingressCodec, Codec2& egressCodec) {
420  maxTransactionHelper(ingressCodec, egressCodec, 50);
421 }
422 
423 template <typename Codec1, typename Codec2>
424 void doNonDefaultMaxTransactionTest(Codec1& ingressCodec, Codec2& egressCodec) {
425  maxTransactionHelper(ingressCodec, egressCodec, 100);
426 }
427 
428 TEST(SPDYCodecTest, DefaultMaxTransactions) {
430 }
431 
432 TEST(SPDYCodecTest, NonDefaultMaxTransactions) {
434 }
435 
436 template <typename Codec1, typename Codec2>
437 void doEmptyHeaderValueTest(Codec1& ingressCodec, Codec2& egressCodec) {
438  uint8_t version = ingressCodec.getVersion();
439  bool emptyAllowed = version != 2;
440  FakeHTTPCodecCallback callbacks;
441  ingressCodec.setCallback(&callbacks);
442  HTTPMessage toSend;
443  toSend.setMethod("GET");
444  toSend.setURL("http://www.foo.com");
445  auto& headers = toSend.getHeaders();
446  headers.set(HTTP_HEADER_HOST, "www.foo.com");
447  headers.set(HTTP_HEADER_PRAGMA, "");
448  headers.set("X-Test1", "yup");
450  std::string pragmaValue;
451  HTTPCodec::StreamID id(1);
452 
453  for (auto i = 0; i < 3; i++) {
454  auto toParse = getSynStream(egressCodec, id + 2 * i,
455  toSend, 0, false, &size);
456  ingressCodec.onIngress(*toParse);
457 
458  EXPECT_EQ(callbacks.sessionErrors, 0);
459  EXPECT_EQ(callbacks.streamErrors, 0);
460  ASSERT_NE(callbacks.msg.get(), nullptr);
461  const auto& parsed = callbacks.msg->getHeaders();
462  EXPECT_EQ(parsed.exists("Pragma"), emptyAllowed);
463  EXPECT_EQ(parsed.exists("pragma"), emptyAllowed);
464  EXPECT_EQ(parsed.getSingleOrEmpty("Pragma"), pragmaValue);
465  EXPECT_EQ(parsed.getSingleOrEmpty("X-Test1"), "yup");
466  // All codecs add the accept-encoding header
467  EXPECT_EQ(parsed.exists("accept-encoding"), true);
468  // SPDY/2 subtracts the Host header, but it should infer it from the
469  // host:port portion of the requested url and present it in the headers
470  EXPECT_EQ(parsed.exists("host"), true);
471  EXPECT_EQ(callbacks.msg->getURL(), "http://www.foo.com");
472  EXPECT_EQ(parsed.size(), emptyAllowed ? 4 : 3);
473  EXPECT_TRUE(size.uncompressed > 0);
474  EXPECT_TRUE(size.compressed > 0);
475 
476  if (i == 0) {
477  headers.add("Pragma", "");
478  }
479  if (i == 1) {
480  pragmaValue = "foo";
481  headers.add("Pragma", pragmaValue);
482  emptyAllowed = true; // SPDY/2 better have it now too
483  }
484  }
485 }
486 
487 TEST(SPDYCodecTest, EmptyHeaderValue) {
489 }
490 
497 TEST(SPDYCodecTest, SynStreamWrongVersion) {
498  SPDYCodec codec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3);
499  FakeHTTPCodecCallback callbacks;
500  auto frame = getVersionedSpdyFrame(synStream, sizeof(synStream), 2);
501  size_t unconsumed = parseSPDY(&codec, frame->data(), frame->length(), -1,
502  callbacks);
503  EXPECT_EQ(unconsumed, 0);
504  // Since the session compression state is inconsistent we need to send a
505  // session error. Expect a GOAWAY with PROTOCOL_ERROR.
506  EXPECT_EQ(callbacks.sessionErrors, 1);
507  EXPECT_EQ(callbacks.streamErrors, 0);
508  EXPECT_EQ(callbacks.lastParseError->getCodecStatusCode(),
510 }
511 
516 { 0x80, 0x02, 0x00, 0x02, 0x01, 0x00, 0x00, 0x04, // length set to 4
517  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
518 };
519 
520 template <typename Codec1, typename Codec2>
521 void doShortSynReplyTest(Codec1& /*ingressCodec*/, Codec2& egressCodec) {
522  FakeHTTPCodecCallback callbacks;
523  egressCodec.setCallback(&callbacks);
524  auto frame = getVersionedSpdyFrame(shortSynReply, sizeof(shortSynReply),
525  egressCodec.getVersion());
526  egressCodec.onIngress(*frame);
527  EXPECT_EQ(callbacks.sessionErrors, 1);
528  EXPECT_EQ(callbacks.streamErrors, 0);
529 }
530 
531 TEST(SPDYCodecTest, ShortSynReply) {
533 }
534 
535 TEST(SPDYCodecTest, SupportsSessionFlowControl) {
536  SPDYCodec spdy3(TransportDirection::UPSTREAM,
537  SPDYVersion::SPDY3);
538  SPDYCodec spdy3_1(TransportDirection::UPSTREAM,
539  SPDYVersion::SPDY3_1);
542 }
543 
544 // Test serializing and deserializing a header that has many values
545 TEST(SPDYCodecTest, HeaderWithManyValues) {
546  const std::string kMultiValued = "X-Multi-Valued";
547  const unsigned kNumValues = 1000;
548 
549  FakeHTTPCodecCallback callbacks;
550  SPDYCodec egressCodec(TransportDirection::UPSTREAM,
551  SPDYVersion::SPDY3);
552  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
553  SPDYVersion::SPDY3);
554  ingressCodec.setCallback(&callbacks);
555 
556  HTTPMessage req;
557  req.setMethod("GET");
558  req.getHeaders().set("HOST", "www.foo.com");
559  req.setURL("https://www.foo.com");
560  for (unsigned i = 0; i < kNumValues; ++i) {
561  req.getHeaders().add(kMultiValued, folly::to<string>("Value", i));
562  }
563  auto syn = getSynStream(egressCodec, 1, req);
564  ingressCodec.onIngress(*syn);
565  EXPECT_EQ(callbacks.messageBegin, 1);
566  EXPECT_EQ(callbacks.headersComplete, 1);
567  EXPECT_EQ(callbacks.messageComplete, 0);
568  EXPECT_EQ(callbacks.streamErrors, 0);
569  EXPECT_EQ(callbacks.sessionErrors, 0);
570  CHECK_NOTNULL(callbacks.msg.get());
571  EXPECT_EQ(callbacks.msg->getHeaders().getNumberOfValues(kMultiValued),
572  kNumValues);
573 }
574 
575 
577  {0x80, 0x03, 0x00, 0x01, 0x01, 0x00, 0x01, 0x13, 0x00, 0x00, 0x00, 0x01,
578  0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x38, 0x30, 0xe3, 0xc6, 0xa7, 0xc2,
579  0x00, 0xf9, 0x00, 0x06, 0xff, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
580  0x05, 0x3a, 0x68, 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77,
581  0x77, 0x2e, 0x66, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x63,
582  0x6f, 0x6d, 0x00, 0x00, 0x00, 0x07, 0x3a, 0x6d, 0x65, 0x74, 0x68, 0x6f,
583  0x64, 0x00, 0x00, 0x00, 0x03, 0x47, 0x45, 0x54, 0x00, 0x00, 0x00, 0x05,
584  0x3a, 0x70, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x35, 0x2f, 0x65, 0x6e,
585  0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x72, 0x65, 0x71, 0x75, 0x65,
586  0x73, 0x74, 0x00, 0x2a, 0x23, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
587  0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x69, 0x74, 0x65, 0x5f,
588  0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x68,
589  0x70, 0x3f, 0x00, 0x00, 0x00, 0x07, 0x3a, 0x73, 0x63, 0x68, 0x65, 0x6d,
590  0x65, 0x00, 0x00, 0x00, 0x05, 0x68, 0x74, 0x74, 0x70, 0x73, 0x00, 0x00,
591  0x00, 0x08, 0x3a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00,
592  0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x00, 0x00,
593  0x00, 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, 0x00, 0x00, 0x03,
594  0x2a, 0x2f, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x70,
595  0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00,
596  0x00, 0x0d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, 0x65, 0x66, 0x6c,
597  0x61, 0x74, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2d,
598  0x61, 0x67, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x11, 0x73, 0x70, 0x64,
599  0x79, 0x6c, 0x61, 0x79, 0x2f, 0x31, 0x2e, 0x33, 0x2e, 0x33, 0x2d, 0x44,
600  0x45, 0x56, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x03, 0x00, 0x07, 0x00,
601  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
602 
603 // Test multiple paths in a message
604 TEST(SPDYCodecTest, MultiplePaths) {
605  FakeHTTPCodecCallback callbacks;
606  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3);
608  sizeof(multiple_path_headers), ingressCodec.getVersion());
609  ingressCodec.setCallback(&callbacks);
610  ingressCodec.onIngress(*frame);
611  EXPECT_EQ(callbacks.streamErrors, 1);
612  EXPECT_EQ(callbacks.sessionErrors, 0);
613 }
614 
615 TEST(SPDYCodecTest, LargeFrameEncoding) {
616  const std::string kMultiValued = "X-Multi-Valued";
617  const unsigned kNumValues = 1000;
618 
619  SPDYCodec codec(TransportDirection::UPSTREAM, SPDYVersion::SPDY3);
620  // This will simulate the condition where we have a very small
621  // compresed headers size compared to the number of headers we
622  // have.
623  codec.setMaxUncompressedHeaders(0);
624  auto req = getGetRequest();
625  for (unsigned i = 0; i < kNumValues; ++i) {
626  req.getHeaders().add(kMultiValued, folly::to<string>("Value", i));
627  }
628  auto syn = getSynStream(codec, 1, req);
629 }
630 
631 // Test serializing and deserializing a header that has many values
632 TEST(SPDYCodecTest, InvalidSettings) {
633  FakeHTTPCodecCallback callbacks;
634 
635  SPDYCodec egressCodec(TransportDirection::UPSTREAM,
636  SPDYVersion::SPDY3);
637  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
638  SPDYVersion::SPDY3);
639  ingressCodec.setCallback(&callbacks);
640 
642  egressCodec.getEgressSettings()->setSetting(
643  SettingsId::INITIAL_WINDOW_SIZE,
645  egressCodec.generateSettings(output);
646  auto ingress = output.move();
647  ingressCodec.onIngress(*ingress);
648  EXPECT_EQ(callbacks.messageBegin, 0);
649  EXPECT_EQ(callbacks.headersComplete, 0);
650  EXPECT_EQ(callbacks.messageComplete, 0);
651  EXPECT_EQ(callbacks.streamErrors, 0);
652  EXPECT_EQ(callbacks.sessionErrors, 1);
653 }
654 
655 TEST(SPDYCodecTest, HeaderWithFin) {
656  FakeHTTPCodecCallback callbacks;
657  SPDYCodec egressCodec(TransportDirection::UPSTREAM,
658  SPDYVersion::SPDY3);
659  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
660  SPDYVersion::SPDY3);
661  ingressCodec.setCallback(&callbacks);
662 
663  HTTPMessage req;
664  req.setMethod("GET");
665  req.getHeaders().set("HOST", "www.foo.com");
666  req.setURL("https://www.foo.com/");
667  auto syn = getSynStream(egressCodec, 1, req, 0, true /* eom */);
668  ingressCodec.onIngress(*syn);
669  EXPECT_EQ(callbacks.messageBegin, 1);
670  EXPECT_EQ(callbacks.headersComplete, 1);
671  EXPECT_EQ(callbacks.messageComplete, 1);
672  EXPECT_EQ(callbacks.streamErrors, 0);
673  EXPECT_EQ(callbacks.sessionErrors, 0);
674  EXPECT_EQ(callbacks.assocStreamId, 0);
675 }
676 
677 TEST(SPDYCodecTest, ServerPush) {
678  FakeHTTPCodecCallback callbacks;
679  SPDYCodec egressCodec(TransportDirection::DOWNSTREAM,
680  SPDYVersion::SPDY3);
681  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
682  SPDYVersion::SPDY3);
683  ingressCodec.setCallback(&callbacks);
684 
685  HTTPMessage push;
686  push.getHeaders().set("HOST", "www.foo.com");
687  push.setURL("https://www.foo.com/");
688  auto syn = getSynStream(egressCodec, 2, push, 1);
689  ingressCodec.onIngress(*syn);
690  EXPECT_EQ(callbacks.messageBegin, 1);
691  EXPECT_EQ(callbacks.headersComplete, 1);
692  EXPECT_EQ(callbacks.messageComplete, 0);
693  EXPECT_EQ(callbacks.streamErrors, 0);
694  EXPECT_EQ(callbacks.sessionErrors, 0);
695  EXPECT_EQ(callbacks.assocStreamId, 1);
696 }
697 
698 TEST(SPDYCodecTest, ServerPushWithStatus) {
699  FakeHTTPCodecCallback callbacks;
700  SPDYCodec egressCodec(TransportDirection::DOWNSTREAM,
701  SPDYVersion::SPDY3);
702  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
703  SPDYVersion::SPDY3);
704  ingressCodec.setCallback(&callbacks);
705 
706  HTTPMessage push;
707  push.getHeaders().set("HOST", "www.foo.com");
708  push.setURL("https://www.foo.com/");
709  push.setPushStatusCode(200);
710  auto syn = getSynStream(egressCodec, 2, push, 1);
711  ingressCodec.onIngress(*syn);
712  EXPECT_EQ(callbacks.messageBegin, 1);
713  EXPECT_EQ(callbacks.headersComplete, 1);
714  EXPECT_EQ(callbacks.messageComplete, 0);
715  EXPECT_EQ(callbacks.streamErrors, 0);
716  EXPECT_EQ(callbacks.sessionErrors, 0);
717  EXPECT_EQ(callbacks.assocStreamId, 1);
718  EXPECT_EQ(callbacks.msg->getPushStatusCode(), 200);
719 }
720 
725 { 0x80, 0x3, 0x0, 0x1, 0x2, 0x0, 0x0, 0x7c,
726  0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x1,
727  0x0, 0x0, 0x38, 0x30, 0xe3, 0xc6, 0xa7, 0xc2,
728  0x0, 0x62, 0x0, 0x9d, 0xff, 0x0, 0x0, 0x0,
729  0x4, 0x0, 0x0, 0x0, 0x5, 0x3a, 0x70, 0x61,
730  0x74, 0x68, 0x0, 0x0, 0x0, 0x14, 0x68, 0x74,
731  0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77,
732  0x77, 0x2e, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x6f,
733  0x6d, 0x2f, 0x0, 0x0, 0x0, 0x7, 0x3a, 0x73,
734  0x63, 0x68, 0x65, 0x6d, 0x65, 0x0, 0x0, 0x0,
735  0x4, 0x68, 0x74, 0x74, 0x70, 0x0, 0x0, 0x0,
736  0x7, 0x3a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
737  0x0, 0x0, 0x0, 0x3, 0x32, 0x30, 0x30, 0x0,
738  0x0, 0x0, 0x8, 0x3a, 0x76, 0x65, 0x72, 0x73,
739  0x69, 0x6f, 0x6e, 0x0, 0x0, 0x0, 0x8, 0x48,
740  0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0,
741  0x0, 0x0, 0xff, 0xff
742 };
743 
744 TEST(SPDYCodecTest, ServerPushHostMissing) {
745  FakeHTTPCodecCallback callbacks;
746  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
747  SPDYVersion::SPDY3);
748  ingressCodec.setCallback(&callbacks);
749 
751  sizeof(pushStreamWithHostMissing));
752  ingressCodec.onIngress(*syn);
753  EXPECT_EQ(callbacks.messageBegin, 0);
754  EXPECT_EQ(callbacks.headersComplete, 0);
755  EXPECT_EQ(callbacks.messageComplete, 0);
756  EXPECT_EQ(callbacks.streamErrors, 1);
757  EXPECT_EQ(callbacks.sessionErrors, 0);
758  EXPECT_EQ(callbacks.assocStreamId, 0);
759 }
760 
765 { 0x80, 0x03, 0x00, 0x01, 0x02, 0x00, 0x00, 0x91,
766  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
767  0x00, 0x00, 0x38, 0x30, 0xe3, 0xc6, 0xa7, 0xc2,
768  0x00, 0x77, 0x00, 0x88, 0xff, 0x00, 0x00, 0x00,
769  0x05, 0x00, 0x00, 0x00, 0x05, 0x3a, 0x68, 0x6f,
770  0x73, 0x74, 0x00, 0x00, 0x00, 0x0b, 0x77, 0x77,
771  0x77, 0x2e, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x6f,
772  0x6d, 0x00, 0x00, 0x00, 0x07, 0x3a, 0x6d, 0x65,
773  0x74, 0x68, 0x6f, 0x64, 0x00, 0x00, 0x00, 0x00,
774  0x00, 0x00, 0x00, 0x05, 0x3a, 0x70, 0x61, 0x74,
775  0x68, 0x00, 0x00, 0x00, 0x14, 0x68, 0x74, 0x74,
776  0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
777  0x2e, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,
778  0x2f, 0x00, 0x00, 0x00, 0x07, 0x3a, 0x73, 0x63,
779  0x68, 0x65, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x04,
780  0x68, 0x74, 0x74, 0x70, 0x00, 0x00, 0x00, 0x08,
781  0x3a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
782  0x00, 0x00, 0x00, 0x08, 0x48, 0x54, 0x54, 0x50,
783  0x2f, 0x31, 0x2e, 0x31, 0x00, 0x00, 0x00, 0xff,
784  0xff
785 };
786 
787 TEST(SPDYCodecTest, ServerPushInvalidId) {
788  FakeHTTPCodecCallback callbacks;
789  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
790  SPDYVersion::SPDY3);
791  ingressCodec.setCallback(&callbacks);
792 
794  sizeof(pushStreamWithOddId));
795  ingressCodec.onIngress(*syn);
796  EXPECT_EQ(callbacks.messageBegin, 0);
797  EXPECT_EQ(callbacks.headersComplete, 0);
798  EXPECT_EQ(callbacks.messageComplete, 0);
799  EXPECT_EQ(callbacks.streamErrors, 0);
800  EXPECT_EQ(callbacks.sessionErrors, 1);
801  EXPECT_EQ(callbacks.assocStreamId, 0);
802 }
803 
808 { 0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x91,
809  0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
810  0x00, 0x00, 0x38, 0x30, 0xe3, 0xc6, 0xa7, 0xc2,
811  0x00, 0x77, 0x00, 0x88, 0xff, 0x00, 0x00, 0x00,
812  0x05, 0x00, 0x00, 0x00, 0x05, 0x3a, 0x68, 0x6f,
813  0x73, 0x74, 0x00, 0x00, 0x00, 0x0b, 0x77, 0x77,
814  0x77, 0x2e, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x6f,
815  0x6d, 0x00, 0x00, 0x00, 0x07, 0x3a, 0x6d, 0x65,
816  0x74, 0x68, 0x6f, 0x64, 0x00, 0x00, 0x00, 0x00,
817  0x00, 0x00, 0x00, 0x05, 0x3a, 0x70, 0x61, 0x74,
818  0x68, 0x00, 0x00, 0x00, 0x14, 0x68, 0x74, 0x74,
819  0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
820  0x2e, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,
821  0x2f, 0x00, 0x00, 0x00, 0x07, 0x3a, 0x73, 0x63,
822  0x68, 0x65, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x04,
823  0x68, 0x74, 0x74, 0x70, 0x00, 0x00, 0x00, 0x08,
824  0x3a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
825  0x00, 0x00, 0x00, 0x08, 0x48, 0x54, 0x54, 0x50,
826  0x2f, 0x31, 0x2e, 0x31, 0x00, 0x00, 0x00, 0xff,
827  0xff
828 };
829 
830 TEST(SPDYCodecTest, ServerPushInvalidFlags) {
831  FakeHTTPCodecCallback callbacks;
832  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
833  SPDYVersion::SPDY3);
834  ingressCodec.setCallback(&callbacks);
835 
838  ingressCodec.onIngress(*syn);
839  EXPECT_EQ(callbacks.messageBegin, 0);
840  EXPECT_EQ(callbacks.headersComplete, 0);
841  EXPECT_EQ(callbacks.messageComplete, 0);
842  EXPECT_EQ(callbacks.streamErrors, 1);
843  EXPECT_EQ(callbacks.sessionErrors, 0);
844  EXPECT_EQ(callbacks.assocStreamId, 0);
845 }
846 
851 { 0x80, 0x03, 0x00, 0x01, 0x02, 0x00, 0x00, 0x91,
852  0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
853  0x00, 0x00, 0x38, 0x30, 0xe3, 0xc6, 0xa7, 0xc2,
854  0x00, 0x77, 0x00, 0x88, 0xff, 0x00, 0x00, 0x00,
855  0x05, 0x00, 0x00, 0x00, 0x05, 0x3a, 0x68, 0x6f,
856  0x73, 0x74, 0x00, 0x00, 0x00, 0x0b, 0x77, 0x77,
857  0x77, 0x2e, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x6f,
858  0x6d, 0x00, 0x00, 0x00, 0x07, 0x3a, 0x6d, 0x65,
859  0x74, 0x68, 0x6f, 0x64, 0x00, 0x00, 0x00, 0x00,
860  0x00, 0x00, 0x00, 0x05, 0x3a, 0x70, 0x61, 0x74,
861  0x68, 0x00, 0x00, 0x00, 0x14, 0x68, 0x74, 0x74,
862  0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
863  0x2e, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,
864  0x2f, 0x00, 0x00, 0x00, 0x07, 0x3a, 0x73, 0x63,
865  0x68, 0x65, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x04,
866  0x68, 0x74, 0x74, 0x70, 0x00, 0x00, 0x00, 0x08,
867  0x3a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
868  0x00, 0x00, 0x00, 0x08, 0x48, 0x54, 0x54, 0x50,
869  0x2f, 0x31, 0x2e, 0x31, 0x00, 0x00, 0x00, 0xff,
870  0xff
871 };
872 
873 TEST(SPDYCodecTest, ServerPushWithoutAssoc) {
874  FakeHTTPCodecCallback callbacks;
875  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
876  SPDYVersion::SPDY3);
877  ingressCodec.setCallback(&callbacks);
878 
880  sizeof(pushStreamWithoutAssoc));
881  ingressCodec.onIngress(*syn);
882  EXPECT_EQ(callbacks.messageBegin, 0);
883  EXPECT_EQ(callbacks.headersComplete, 0);
884  EXPECT_EQ(callbacks.messageComplete, 0);
885  EXPECT_EQ(callbacks.streamErrors, 0);
886  EXPECT_EQ(callbacks.sessionErrors, 1);
887  EXPECT_EQ(callbacks.assocStreamId, 0);
888 }
889 
890 TEST(SPDYCodecTest, StatusReason) {
891  FakeHTTPCodecCallback callbacks;
892  SPDYCodec egressCodec(TransportDirection::DOWNSTREAM,
893  SPDYVersion::SPDY3);
894  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
895  SPDYVersion::SPDY3);
896  ingressCodec.setCallback(&callbacks);
897 
898  HTTPMessage resp;
899  resp.setStatusCode(200);
900  auto syn = getSynStream(egressCodec, 1, resp, 0);
901  ingressCodec.onIngress(*syn);
902  EXPECT_EQ(callbacks.messageBegin, 1);
903  EXPECT_EQ(callbacks.headersComplete, 1);
904  EXPECT_EQ(callbacks.messageComplete, 0);
905  EXPECT_EQ(callbacks.streamErrors, 0);
906  EXPECT_EQ(callbacks.sessionErrors, 0);
907  EXPECT_EQ(callbacks.msg->getStatusCode(), 200);
908  EXPECT_EQ(callbacks.msg->getStatusMessage(), "");
909  callbacks.reset();
910 
911  resp.setStatusCode(200);
912  resp.setStatusMessage("Awesome");
913  syn = getSynStream(egressCodec, 1, resp, 0);
914  ingressCodec.onIngress(*syn);
915  EXPECT_EQ(callbacks.messageBegin, 1);
916  EXPECT_EQ(callbacks.headersComplete, 1);
917  EXPECT_EQ(callbacks.messageComplete, 0);
918  EXPECT_EQ(callbacks.streamErrors, 0);
919  EXPECT_EQ(callbacks.sessionErrors, 0);
920  EXPECT_EQ(callbacks.msg->getStatusCode(), 200);
921  EXPECT_EQ(callbacks.msg->getStatusMessage(), "Awesome");
922  callbacks.reset();
923 
924  // Out of range
925  resp.setStatusCode(2000);
926  resp.setStatusMessage("10x OK");
927  syn = getSynStream(egressCodec, 1, resp, 0);
928  ingressCodec.onIngress(*syn);
929  EXPECT_EQ(callbacks.messageBegin, 0);
930  EXPECT_EQ(callbacks.headersComplete, 0);
931  EXPECT_EQ(callbacks.messageComplete, 0);
932  EXPECT_EQ(callbacks.streamErrors, 1);
933  EXPECT_EQ(callbacks.sessionErrors, 0);
934  EXPECT_TRUE(callbacks.lastParseError->hasCodecStatusCode());
935  EXPECT_EQ(callbacks.lastParseError->getCodecStatusCode(),
937  callbacks.reset();
938 
939  resp.setStatusCode(64);
940  resp.setStatusMessage("Ought to be enough for anybody");
941  syn = getSynStream(egressCodec, 1, resp, 0);
942  ingressCodec.onIngress(*syn);
943  EXPECT_EQ(callbacks.messageBegin, 0);
944  EXPECT_EQ(callbacks.headersComplete, 0);
945  EXPECT_EQ(callbacks.messageComplete, 0);
946  EXPECT_EQ(callbacks.streamErrors, 1);
947  EXPECT_EQ(callbacks.sessionErrors, 0);
948  EXPECT_TRUE(callbacks.lastParseError->hasCodecStatusCode());
949  EXPECT_EQ(callbacks.lastParseError->getCodecStatusCode(),
951  callbacks.reset();
952 }
953 
954 TEST(SPDYCodecTest, UpstreamPing) {
956  FakeHTTPCodecCallback callbacks;
957  SPDYCodec egressCodec(TransportDirection::UPSTREAM,
958  SPDYVersion::SPDY3);
959  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
960  SPDYVersion::SPDY3);
961  ingressCodec.setCallback(&callbacks);
962 
963  // Send a reply with no corresponding ping request
964  egressCodec.generatePingReply(buf, 2);
965  auto pingReply = buf.move();
966  ingressCodec.onIngress(*pingReply);
967  ASSERT_EQ(callbacks.recvPingReply, 0); // should be ignored
968 
969  auto lastRequest = callbacks.recvPingRequest;
970  for (unsigned i = 0; i < 10; ++i) {
971  egressCodec.generatePingRequest(buf);
972  auto pingReq = buf.move();
973  ingressCodec.onIngress(*pingReq);
974  ASSERT_GT(callbacks.recvPingRequest, lastRequest);
975  ASSERT_EQ(callbacks.recvPingRequest % 2, 1);
976  lastRequest = callbacks.recvPingRequest;
977  }
978 }
979 
980 TEST(SPDYCodecTest, DownstreamPing) {
982  FakeHTTPCodecCallback callbacks;
983  SPDYCodec egressCodec(TransportDirection::DOWNSTREAM,
984  SPDYVersion::SPDY3);
985  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
986  SPDYVersion::SPDY3);
987  ingressCodec.setCallback(&callbacks);
988 
989  // Send a reply with no corresponding ping request
990  egressCodec.generatePingReply(buf, 1);
991  auto pingReply = buf.move();
992  ingressCodec.onIngress(*pingReply);
993  ASSERT_EQ(callbacks.recvPingReply, 0); // should be ignored
994 
995  auto lastRequest = callbacks.recvPingRequest;
996  for (unsigned i = 0; i < 10; ++i) {
997  egressCodec.generatePingRequest(buf);
998  auto pingReq = buf.move();
999  ingressCodec.onIngress(*pingReq);
1000  ASSERT_GT(callbacks.recvPingRequest, lastRequest);
1001  ASSERT_EQ(callbacks.recvPingRequest % 2, 0);
1002  lastRequest = callbacks.recvPingRequest;
1003  }
1004 }
1005 
1006 TEST(SPDYCodecTest, DateHeader) {
1007  FakeHTTPCodecCallback callbacks;
1008  SPDYCodec egressCodec(TransportDirection::DOWNSTREAM,
1009  SPDYVersion::SPDY3);
1010  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
1011  SPDYVersion::SPDY3);
1012  ingressCodec.setCallback(&callbacks);
1013 
1014  HTTPMessage resp;
1015  resp.setStatusCode(200);
1016  auto syn = getSynStream(egressCodec, 1, resp, 0);
1017  ingressCodec.onIngress(*syn);
1018  EXPECT_EQ(callbacks.messageBegin, 1);
1019  EXPECT_EQ(callbacks.headersComplete, 1);
1020  EXPECT_EQ(callbacks.messageComplete, 0);
1021  EXPECT_EQ(callbacks.streamErrors, 0);
1022  EXPECT_EQ(callbacks.sessionErrors, 0);
1023  EXPECT_TRUE(callbacks.msg->getHeaders().exists(HTTP_HEADER_DATE));
1024 }
1025 
1026 // SYN_STREAM includes ~100k header name with 50k one-byte values
1028 { 0x80, 0x03, 0x00, 0x01, 0x01, 0x00, 0x02, 0x11,
1029  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1030  0x60, 0x00, 0x38, 0xea, 0xe3, 0xc6, 0xa7, 0xc2,
1031  0xec, 0xd4, 0x31, 0x0e, 0x82, 0x40, 0x10, 0x46,
1032  0x61, 0x8c, 0x85, 0x1a, 0x43, 0x6f, 0x69, 0x4d,
1033  0x31, 0x24, 0xda, 0x6d, 0x4f, 0xb8, 0x80, 0x17,
1034  0x00, 0x8d, 0xa1, 0xd0, 0x30, 0xc9, 0x6e, 0x01,
1035  0x57, 0xb7, 0x72, 0x18, 0x49, 0x28, 0xe4, 0x08,
1036  0xef, 0xab, 0x61, 0x93, 0x4d, 0xfe, 0x7d, 0xb6,
1037  0xa3, 0xc3, 0xf4, 0x9c, 0xc2, 0x1c, 0x84, 0x93,
1038  0x2d, 0x5a, 0xfa, 0x94, 0x7a, 0x89, 0xad, 0x3c,
1039  0x2d, 0xbd, 0xad, 0x8d, 0x4f, 0xee, 0x1e, 0x8d,
1040  0x5d, 0x58, 0xa6, 0x5d, 0x57, 0x37, 0xff, 0x4d,
1041  0x1b, 0x0f, 0xd8, 0xb1, 0xfc, 0x8d, 0x5c, 0xb4,
1042  0x53, 0xff, 0x32, 0x5a, 0x38, 0xdf, 0x5e, 0xd7,
1043  0x2e, 0x25, 0x9d, 0xc6, 0xbf, 0x0f, 0xeb, 0x9b,
1044  0x5f, 0xc2, 0xbe, 0x2d, 0xca, 0x62, 0xbd, 0xe6,
1045  0xb9, 0x5f, 0xf2, 0x3c, 0xdf, 0xf2, 0xef, 0x81,
1046  0xe6, 0x51, 0x1f, 0xe3, 0xab, 0x19, 0xed, 0xc4,
1047  0x8b, 0x5c, 0xb3, 0xcd, 0x27, 0x1b, 0x00, 0x00,
1048  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1049  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
1050  0xb2, 0x07, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00,
1051  0x40, 0xfe, 0xaf, 0x8d, 0xa0, 0xaa, 0xaa, 0xaa,
1052  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1053  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1054  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1055  0xaa, 0xaa, 0xaa, 0xaa, 0xc2, 0x1e, 0x1c, 0x08,
1056  0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0xbf, 0x36,
1057  0x82, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1058  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1059  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1060  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1061  0x0a, 0x7b, 0x70, 0x20, 0x00, 0x00, 0x00, 0x00,
1062  0x00, 0xe4, 0xff, 0xda, 0x08, 0xaa, 0xaa, 0xaa,
1063  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1064  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1065  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1066  0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0xec, 0xc1, 0x41,
1067  0x01, 0x00, 0x00, 0x04, 0x04, 0xb0, 0x53, 0x47,
1068  0x3f, 0xe5, 0xbd, 0x14, 0x10, 0x61, 0x1b, 0x00,
1069  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1070  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1071  0x00, 0xf0, 0x48, 0x6d, 0x7a, 0xa2, 0xaa, 0xaa,
1072  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1073  0x7a, 0xec, 0xc2, 0x01, 0x09, 0x00, 0x00, 0x00,
1074  0x00, 0x90, 0xff, 0xaf, 0x1d, 0x11, 0x55, 0x55,
1075  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1076  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1077  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1078  0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x76, 0xe1,
1079  0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xff,
1080  0xd7, 0x8e, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1081  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1082  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1083  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1084  0xaa, 0xaa, 0x0a, 0xbb, 0x70, 0x40, 0x02, 0x00,
1085  0x00, 0x00, 0x00, 0xe4, 0xff, 0x6b, 0x47, 0x44,
1086  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1087  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1088  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1089  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x85,
1090  0x5d, 0x38, 0xa6, 0x01, 0x00, 0x00, 0x60, 0x18,
1091  0xe4, 0x67, 0xfe, 0x05, 0xf6, 0x9f, 0x06, 0x02,
1092  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1093  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1094  0x00, 0x00, 0x00, 0xbc, 0x05, 0x00, 0x00, 0xff,
1095  0xff
1096 };
1097 
1098 // Ensure the codec can handle a malicious packet intended to exhaust server
1099 // resources
1100 TEST(SPDYCodecTest, HeaderDoS) {
1101  FakeHTTPCodecCallback callbacks;
1102  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
1103  SPDYVersion::SPDY3);
1104  ingressCodec.setCallback(&callbacks);
1105 
1107  sizeof(multiValuedHeaderAttack));
1108 
1109  ingressCodec.onIngress(*attack);
1110  EXPECT_EQ(callbacks.messageBegin, 0);
1111  EXPECT_EQ(callbacks.headersComplete, 0);
1112  EXPECT_EQ(callbacks.messageComplete, 0);
1113  EXPECT_EQ(callbacks.streamErrors, 1);
1114  EXPECT_EQ(callbacks.sessionErrors, 1);
1115 }
1116 
1117 // Make sure SPDYCodec behaves correctly when we generate and receive double
1118 // GOAWAYs.
1119 TEST(SPDYCodecTest, DoubleGoawayServer) {
1120  FakeHTTPCodecCallback callbacks;
1121  SPDYCodec egressCodec(TransportDirection::DOWNSTREAM,
1122  SPDYVersion::SPDY3);
1123  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
1124  SPDYVersion::SPDY3);
1125 
1126  egressCodec.enableDoubleGoawayDrain();
1127  ingressCodec.setCallback(&callbacks);
1128  egressCodec.setCallback(&callbacks);
1129 
1130  unsigned ack = std::numeric_limits<int32_t>::max();
1131  auto f = [&] () {
1133  egressCodec.generateGoaway(output, ack, ErrorCode::NO_ERROR);
1134  auto ingress = output.move();
1135  ingressCodec.onIngress(*ingress);
1136  ack -= 2;
1137  };
1138 
1139  EXPECT_TRUE(egressCodec.isReusable());
1140  EXPECT_FALSE(egressCodec.isWaitingToDrain());
1141  EXPECT_TRUE(ingressCodec.isReusable());
1142  f();
1143  // server spdy codec remains reusable after the first goaway
1144  EXPECT_TRUE(egressCodec.isReusable());
1145  EXPECT_TRUE(egressCodec.isWaitingToDrain());
1146  f();
1147  EXPECT_FALSE(egressCodec.isReusable());
1148  EXPECT_FALSE(egressCodec.isWaitingToDrain());
1149 
1150  EXPECT_EQ(2, callbacks.goaways);
1151 }
1152 
1153 TEST(SPDYCodecTest, DoubleGoawayClient) {
1154  FakeHTTPCodecCallback callbacks;
1155  SPDYCodec egressCodec(TransportDirection::UPSTREAM,
1156  SPDYVersion::SPDY3);
1157  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
1158  SPDYVersion::SPDY3);
1159 
1160  egressCodec.enableDoubleGoawayDrain();
1161  ingressCodec.setCallback(&callbacks);
1162  egressCodec.setCallback(&callbacks);
1163 
1164  unsigned ack = std::numeric_limits<int32_t>::max();
1165  auto f = [&] () {
1167  egressCodec.generateGoaway(output, ack, ErrorCode::NO_ERROR);
1168  auto ingress = output.move();
1169  ingressCodec.onIngress(*ingress);
1170  ack -= 2;
1171  };
1172 
1173  EXPECT_TRUE(egressCodec.isReusable());
1174  EXPECT_FALSE(egressCodec.isWaitingToDrain());
1175  f();
1176  // client spdy codec not reusable after the first goaway
1177  EXPECT_FALSE(egressCodec.isReusable());
1178  EXPECT_TRUE(egressCodec.isWaitingToDrain());
1179  EXPECT_FALSE(ingressCodec.isReusable());
1180  f();
1181  EXPECT_FALSE(egressCodec.isReusable());
1182  EXPECT_FALSE(egressCodec.isWaitingToDrain());
1183  EXPECT_FALSE(ingressCodec.isReusable());
1184 
1185  EXPECT_EQ(2, callbacks.goaways);
1186 }
1187 
1188 
1189 TEST(SPDYCodecTest, SingleGoawayClient) {
1190  FakeHTTPCodecCallback callbacks;
1191  SPDYCodec egressCodec(TransportDirection::UPSTREAM,
1192  SPDYVersion::SPDY3);
1193  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
1194  SPDYVersion::SPDY3);
1195 
1196  ingressCodec.setCallback(&callbacks);
1197  egressCodec.setCallback(&callbacks);
1198 
1199  unsigned ack = 0;
1200  auto f = [&] () {
1202  egressCodec.generateGoaway(output, ack, ErrorCode::NO_ERROR);
1203  auto ingress = output.move();
1204  ingressCodec.onIngress(*ingress);
1205  ack -= 2;
1206  };
1207 
1208  EXPECT_TRUE(egressCodec.isReusable());
1209  EXPECT_TRUE(egressCodec.isWaitingToDrain());
1210  f();
1211  // client spdy codec not reusable after the first goaway
1212  EXPECT_FALSE(egressCodec.isReusable());
1213  EXPECT_FALSE(egressCodec.isWaitingToDrain());
1214  EXPECT_FALSE(ingressCodec.isReusable());
1215 
1216  EXPECT_EQ(1, callbacks.goaways);
1217 }
1218 
1219 // Two packets:
1220 // - first one has an invalid header nanme
1221 // - second one has an empty header block
1223 { 0x80, 0x03, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x14,
1224  0xf7, 0x76, 0x2d, 0x37, 0x78, 0x9c, 0x93, 0x60,
1225  0x00, 0x03, 0x75, 0x06, 0xbd, 0x76, 0x21, 0xb2,
1226  0xd0, 0xd9, 0x54, 0x91, 0x80, 0x03, 0x00, 0x01,
1227  0x4e, 0x00, 0x00, 0x0a, 0xbe, 0x14, 0x31, 0x55,
1228  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1229  0x00
1230 };
1231 
1232 // Try to trick the codec into leaving the HeaderList in an inconsistent state
1233 // (a header name without a corresponding value), and parsing this inconsistent
1234 // HeaderList
1235 TEST(SPDYCodecTest, OddHeaderListTest) {
1236  FakeHTTPCodecCallback callbacks;
1237  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
1238  SPDYVersion::SPDY3);
1239  ingressCodec.setCallback(&callbacks);
1240 
1242  sizeof(invalidHeaderPlusEmptyBlock));
1243 
1244  ingressCodec.onIngress(*attack);
1245  EXPECT_EQ(callbacks.messageBegin, 1);
1246  EXPECT_EQ(callbacks.headersComplete, 1);
1247  EXPECT_EQ(callbacks.streamErrors, 1);
1248 }
1249 
1250 // Send a RST_STREAM for stream=1 while parsing a SYN_STREAM+FIN for stream=3.
1251 // Stream 3 should be unaffected
1252 TEST(SPDYCodecTest, SendRstParsingFrame) {
1254  SPDYCodec egressCodec(TransportDirection::UPSTREAM,
1255  SPDYVersion::SPDY3_1);
1256  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
1257  SPDYVersion::SPDY3_1);
1260 
1261  InSequence enforceOrder;
1262 
1263  EXPECT_CALL(callbacks, onHeadersComplete(3, _))
1264  .WillOnce(InvokeWithoutArgs([&] {
1265  ingressCodec.generateRstStream(ingressCodecQueue,
1266  1, ErrorCode::CANCEL);
1267  }));
1268  EXPECT_CALL(callbacks, onMessageComplete(3, false));
1269 
1270  ingressCodec.setCallback(&callbacks);
1271  auto syn = getSynStream(egressCodec, 3);
1272  egressCodecQueue.append(std::move(syn));
1273  egressCodec.generateEOM(egressCodecQueue, 3);
1274  auto ingress = egressCodecQueue.move();
1275  ingress->coalesce();
1276  ingressCodec.onIngress(*ingress);
1277 }
1278 
1280  0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x91,
1281  0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
1282  0x00, 0x00, 0x38, 0x30, 0xe3, 0xc6, 0xa7, 0xc2,
1283  0x00, 0x77, 0x00, 0x88, 0xff, 0x00, 0x00, 0x00,
1284  0x05, 0x00, 0x00, 0x00, 0x05, 0x3a, 0x68, 0x6f,
1285  0x73, 0x74, 0x00, 0x00, 0x00, 0x0b, 0x77, 0x77,
1286  0x77, 0x2e, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x6f,
1287  0x6d, 0x00, 0x00, 0x00, 0x77, 0x3a, 0x6d, 0x65,
1288  0x74, 0x68, 0x6f, 0x64, 0x00, 0x00, 0x00, 0x00,
1289  0x00, 0x00, 0x00, 0x05, 0x3a, 0x70, 0x61, 0x74,
1290  0x68, 0x00, 0x13, 0x00, 0x14, 0x68, 0x74, 0x74,
1291  0x39, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
1292  0x2e, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,
1293  0x2f, 0x00, 0x00, 0x00, 0x07, 0x3a, 0x73, 0x63,
1294  0x68, 0x65, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x04,
1295  0x68, 0x74, 0x74, 0x70, 0x00, 0x00, 0x00, 0x08,
1296  0x3a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
1297  0x00, 0x00, 0x00, 0x08, 0x48, 0x54, 0x54, 0x50,
1298  0x2f, 0x31, 0x2e, 0x31, 0x00, 0x00, 0x00, 0xff,
1299  0xff
1300 };
1301 // Ensure we generate a session-level error if the number of name values
1302 // exceeds the size of our current buffer.
1303 TEST(SPDYCodecTest, BadNumNameValues) {
1304  FakeHTTPCodecCallback callbacks;
1305  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
1306  SPDYVersion::SPDY3_1);
1307  ingressCodec.setCallback(&callbacks);
1308 
1310  sizeof(invalidNumNameValuesBlock));
1311 
1312  ingressCodec.onIngress(*attack);
1313  EXPECT_EQ(callbacks.messageBegin, 0);
1314  EXPECT_EQ(callbacks.headersComplete, 0);
1315  EXPECT_EQ(callbacks.streamErrors, 0);
1316  EXPECT_EQ(callbacks.sessionErrors, 1);
1317 }
1318 
1320  0x80, 0x03, 0x00, 0x04, 0xee, 0x00, 0x00, 0x01, 0x00, 0x00
1321 };
1322 // Make sure we reject SETTINGS frames that are too short with GOAWAY
1323 TEST(SPDYCodecTest, ShortSettings) {
1324  FakeHTTPCodecCallback callbacks;
1325  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
1326  SPDYVersion::SPDY3_1);
1327  ingressCodec.setCallback(&callbacks);
1328 
1330  sizeof(kShortSettings));
1331 
1332  ingressCodec.onIngress(*attack);
1333  EXPECT_EQ(callbacks.messageBegin, 0);
1334  EXPECT_EQ(callbacks.headersComplete, 0);
1335  EXPECT_EQ(callbacks.streamErrors, 0);
1336  EXPECT_EQ(callbacks.sessionErrors, 1);
1337 }
1338 
1339 TEST(SPDYCodecTest, SegmentedHeaderBlock) {
1340  SPDYCodec egressCodec(TransportDirection::UPSTREAM,
1341  SPDYVersion::SPDY3_1);
1342  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
1343  SPDYVersion::SPDY3_1);
1344  // generate huge string to use as a header value
1345  string huge;
1346  uint32_t size = 20000;
1347  char ch = 'a';
1348  for (uint32_t i = 0; i < size; i++) {
1349  huge.push_back(ch);
1350  if (ch == 'z') {
1351  ch = 'a';
1352  } else {
1353  ch++;
1354  }
1355  }
1356  HTTPMessage req;
1357  req.setMethod("GET");
1358  req.setURL("http://www.facebook.com");
1359  auto& reqHeaders = req.getHeaders();
1360  reqHeaders.set("HOST", "www.facebook.com");
1361  // setting this huge header value will cause allocation of a separate IOBuf
1362  reqHeaders.set("X-FB-Huge", huge);
1363  auto buf = getSynStream(egressCodec, 1, req);
1364  FakeHTTPCodecCallback callbacks;
1365  ingressCodec.setCallback(&callbacks);
1366  ingressCodec.onIngress(*buf);
1367  EXPECT_EQ(callbacks.streamErrors, 0);
1368  EXPECT_EQ(callbacks.sessionErrors, 0);
1369  EXPECT_EQ(callbacks.headersComplete, 1);
1370  EXPECT_EQ(callbacks.msg->getHeaders().getSingleOrEmpty("x-fb-huge").size(),
1371  size);
1372 
1373  // do it for responses
1374  HTTPMessage resp;
1375  resp.setStatusCode(200);
1376  resp.setStatusMessage("OK");
1377  auto& respHeaders = resp.getHeaders();
1378  respHeaders.set("X-FB-Huge", huge);
1379  auto buf2 = getSynStream(ingressCodec, 1, resp);
1380  callbacks.reset();
1381  egressCodec.setCallback(&callbacks);
1382  egressCodec.onIngress(*buf2);
1383  EXPECT_EQ(callbacks.streamErrors, 0);
1384  EXPECT_EQ(callbacks.sessionErrors, 0);
1385  EXPECT_EQ(callbacks.headersComplete, 1);
1386  EXPECT_EQ(callbacks.msg->getHeaders().getSingleOrEmpty("x-fb-huge").size(),
1387  size);
1388 }
1389 
1391  0x80, 0x03, 0x00, 0x01, 0x48, 0x00, 0x00, 0x1a, 0xf6, 0xf6, 0x1a, 0xb5,
1392  0x00, 0x00, 0x00, 0x00, 0x17, 0x28, 0x28, 0x53, 0x62, 0x60, 0x60, 0x10,
1393  0x60, 0x60, 0x60, 0x60, 0xb4, 0x1a, 0xbc, 0x84, 0xa4, 0xa4
1394 };
1395 
1396 // Test a case where we use a single colon as a header name
1397 TEST(SPDYCodecTest, ColonHeaders) {
1398  FakeHTTPCodecCallback callbacks;
1399  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
1400  SPDYVersion::SPDY3_1);
1401  ingressCodec.setCallback(&callbacks);
1402 
1403  auto testBuf = folly::IOBuf::copyBuffer(kColonHeaders,
1404  sizeof(kColonHeaders));
1405 
1406  ingressCodec.onIngress(*testBuf);
1407  EXPECT_EQ(callbacks.headersComplete, 0);
1408  EXPECT_EQ(callbacks.streamErrors, 1);
1409  EXPECT_EQ(callbacks.sessionErrors, 0);
1410 }
1411 
1412 TEST(SPDYCodecTest, StreamIdOverflow) {
1413  SPDYCodec codec(TransportDirection::UPSTREAM,
1414  SPDYVersion::SPDY3_1);
1415 
1416  HTTPCodec::StreamID streamId;
1418  while (codec.isReusable()) {
1419  streamId = codec.createStream();
1420  }
1422 }
1423 
1425  0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c,
1426  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1427  0x00, 0x00, 0x78, 0xbb, 0xe3, 0xc6, 0xa7, 0xc2,
1428  0x02, 0xa6, 0x23, 0xc6, 0xff, 0x40, 0x00, 0x00,
1429  0x00, 0x00, 0xff, 0xff
1430 };
1431 
1435 TEST(SPDYCodecTest, BadNVBlock) {
1436  FakeHTTPCodecCallback callbacks;
1437  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
1438  SPDYVersion::SPDY3_1);
1439 
1440  auto testBuf = IOBuf::copyBuffer(kBufBadNVBlock, sizeof(kBufBadNVBlock));
1441  ingressCodec.setCallback(&callbacks);
1442  ingressCodec.onIngress(*testBuf);
1443  EXPECT_EQ(callbacks.headersComplete, 0);
1444  EXPECT_EQ(callbacks.streamErrors, 0);
1445  EXPECT_EQ(callbacks.sessionErrors, 1);
1446 }
1447 
1449 
1450  public:
1452  : HTTPParallelCodecTest(upstreamCodec_, downstreamCodec_) {}
1453 
1454  protected:
1455  SPDYCodec upstreamCodec_{TransportDirection::UPSTREAM, SPDYVersion::SPDY3_1};
1456  SPDYCodec downstreamCodec_{TransportDirection::DOWNSTREAM,
1457  SPDYVersion::SPDY3_1};
1458 };
1459 
1460 TEST_F(SPDYCodecTestF, GoawayHandling) {
1461  // send request
1462  HTTPMessage req = getGetRequest();
1464  size.uncompressed = size.compressed = 0;
1465  upstreamCodec_.generateHeader(output_, 1, req, true, &size);
1466  EXPECT_GT(size.uncompressed, 0);
1467  parse();
1468  callbacks_.expectMessage(true, 2, "/");
1469  callbacks_.reset();
1470 
1471  SetUpUpstreamTest();
1472  // drain after this message
1473  downstreamCodec_.generateGoaway(output_, 1, ErrorCode::NO_ERROR);
1474  parseUpstream();
1475  // upstream cannot generate id > 1
1476  upstreamCodec_.generateHeader(output_, 3, req, false, &size);
1477  EXPECT_EQ(size.uncompressed, 0);
1478  upstreamCodec_.generateWindowUpdate(output_, 3, 100);
1479  upstreamCodec_.generateBody(output_, 3, makeBuf(10), HTTPCodec::NoPadding,
1480  false);
1481  upstreamCodec_.generatePriority(output_, 3,
1482  HTTPMessage::HTTPPriority(0, true, 1));
1483  upstreamCodec_.generateEOM(output_, 3);
1484  upstreamCodec_.generateRstStream(output_, 3, ErrorCode::CANCEL);
1485  EXPECT_EQ(output_.chainLength(), 0);
1486 
1487  // send a push promise that will be rejected by downstream
1488  req.setPushStatusCode(200);
1489  req.getHeaders().add("foomonkey", "george");
1490  downstreamCodec_.generatePushPromise(output_, 2, req, 1, false, &size);
1491  EXPECT_GT(size.uncompressed, 0);
1492  // window update for push doesn't make any sense, but whatever
1493  downstreamCodec_.generateWindowUpdate(output_, 2, 100);
1494  downstreamCodec_.generateBody(output_, 2, makeBuf(10), HTTPCodec::NoPadding,
1495  false);
1496 
1497  // tell the upstream no pushing, and parse the first batch
1499  upstreamCodec_.generateGoaway(dummy, 0, ErrorCode::NO_ERROR);
1500  parseUpstream();
1501 
1502  downstreamCodec_.generatePriority(output_, 2,
1503  HTTPMessage::HTTPPriority(0, true, 1));
1504  downstreamCodec_.generateEOM(output_, 2);
1505  downstreamCodec_.generateRstStream(output_, 2, ErrorCode::CANCEL);
1506 
1507  // send a response that will be accepted, headers should be ok
1508  HTTPMessage resp;
1509  resp.setStatusCode(200);
1510  downstreamCodec_.generateHeader(output_, 1, resp, true, &size);
1511  EXPECT_GT(size.uncompressed, 0);
1512 
1513  // parse the remainder
1514  parseUpstream();
1515  callbacks_.expectMessage(true, 1, 200);
1516 }
size_t parse(const char *buf, size_t len)
Definition: test.c:1591
uint8_t multiValuedHeaderAttack[]
#define ASSERT_GT(val1, val2)
Definition: gtest.h:1976
uint8_t badType[]
size_t onIngress(const folly::IOBuf &buf) override
Definition: SPDYCodec.cpp:234
uint8_t pushStreamWithHostMissing[]
void setCallback(Callback *callback) override
uint8_t invalidNumNameValuesBlock[]
HTTPCodec::StreamID assocStreamId
Definition: TestUtils.h:370
void append(std::unique_ptr< folly::IOBuf > &&buf, bool pack=false)
Definition: IOBufQueue.cpp:143
const uint32_t kInitialWindow
auto f
uint8_t multiple_path_headers[]
unique_ptr< folly::IOBuf > getVersionedSpdyFrame(const uint8_t *bytes, size_t len, uint8_t version)
void maxTransactionHelper(Codec1 &ingressCodec, Codec2 &egressCodec, uint32_t parallel)
uint8_t getVersion() const
Definition: SPDYCodec.cpp:1023
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
LogLevel max
Definition: LogLevel.cpp:31
std::unique_ptr< HTTPException > lastParseError
Definition: TestUtils.h:405
void setStatusMessage(T &&msg)
Definition: HTTPMessage.h:242
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
uint8_t shortSynReply[]
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
CodecFactory codec
const std::string kNamePathv3
STL namespace.
void setMaxFrameLength(uint32_t maxFrameLength)
Definition: SPDYCodec.cpp:189
void doShortSynReplyTest(Codec1 &, Codec2 &egressCodec)
std::function< bool()> getStopFn()
Definition: TestUtils.h:291
void setNextEgressStreamId(StreamID nextEgressStreamID)
std::unique_ptr< folly::IOBuf > move()
Definition: IOBufQueue.h:459
bool supportsSessionFlowControl() const override
Definition: SPDYCodec.cpp:214
static http_parser_settings settings
Definition: test.c:1529
size_t generateRstStream(folly::IOBufQueue &writeBuf, StreamID txn, ErrorCode statusCode) override
Definition: SPDYCodec.cpp:824
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
PolymorphicAction< internal::InvokeWithoutArgsAction< FunctionImpl > > InvokeWithoutArgs(FunctionImpl function_impl)
bool isReusable() const override
void setPushStatusCode(const uint16_t status)
auto ch
uint8_t pushStreamWithoutAssoc[]
std::size_t getNumSettings() const
Definition: HTTPSettings.h:58
ProtocolVersion version
std::unique_ptr< folly::IOBuf > makeBuf(uint32_t size)
Definition: ZlibTests.cpp:26
size_t generatePingReply(folly::IOBufQueue &writeBuf, uint64_t uniqueID) override
Definition: SPDYCodec.cpp:924
size_t generateEOM(folly::IOBufQueue &writeBuf, StreamID stream) override
Definition: SPDYCodec.cpp:812
void set(folly::StringPiece name, const std::string &value)
Definition: HTTPHeaders.h:119
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
ParseURL setURL(T &&url)
Definition: HTTPMessage.h:183
static Options cacheChainLength()
Definition: IOBufQueue.h:83
HTTPSettings * getEgressSettings() override
Definition: SPDYCodec.h:107
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
void dummy()
const std::string kNameMethodv3
#define permuteTest(f)
void doEmptyHeaderValueTest(Codec1 &ingressCodec, Codec2 &egressCodec)
const std::string kNameVersionv3
uint8_t pushStreamWithoutUnidirectional[]
Parallel parallel(Ops ops, size_t threads=0)
Definition: Parallel.h:88
StreamID createStream() override
size_t parseSPDY(SPDYCodec *codec, const uint8_t *inputData, uint32_t length, int32_t atOnce, FakeHTTPCodecCallback &callbacks)
HTTPHeaders & getHeaders()
Definition: HTTPMessage.h:273
auto huge
const std::string kNameHostv3
void doNonDefaultMaxTransactionTest(Codec1 &ingressCodec, Codec2 &egressCodec)
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
void enableDoubleGoawayDrain() override
void setMethod(HTTPMethod method)
std::tuple< uint32_t, bool, uint8_t > HTTPPriority
Definition: HTTPMessage.h:592
const std::string kNameStatusv3
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
unique_ptr< folly::IOBuf > getSynStream(Codec &egressCodec, uint32_t streamID, const HTTPMessage &msg, uint32_t assocStreamId=SPDYCodec::NoStream, bool eom=false, HTTPHeaderSize *size=nullptr)
uint8_t spdy3UnknownCtlFrame[]
HTTPMessage getGetRequest(const std::string &url)
Definition: TestUtils.cpp:76
void unsetSetting(SettingsId id)
const char * string
Definition: Conv.cpp:212
uint8_t synStream[]
const std::string kNameSchemev3
bool isWaitingToDrain() const override
SettingsValue value
Definition: HTTPSettings.h:32
#define EXPECT_CALL(obj, call)
uint64_t StreamID
Definition: HTTPCodec.h:49
const internal::AnythingMatcher _
uint8_t pushStreamWithOddId[]
void add(folly::StringPiece name, folly::StringPiece value)
Definition: HTTPHeaders.cpp:52
#define ASSERT_NE(val1, val2)
Definition: gtest.h:1960
void callFunction(F f, V version)
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
const uint8_t kBufBadNVBlock[]
std::unique_ptr< HTTPMessage > msg
Definition: TestUtils.h:404
const uint8_t kShortSettings[]
void doDefaultMaxTransactionTest(Codec1 &ingressCodec, Codec2 &egressCodec)
const uint32_t kMaxConcurrentStreams
size_t generateSettings(folly::IOBufQueue &writeBuf) override
Definition: SPDYCodec.cpp:941
static std::unique_ptr< IOBuf > copyBuffer(const void *buf, std::size_t size, std::size_t headroom=0, std::size_t minTailroom=0)
Definition: IOBuf.h:1587
uint8_t longPing[]
uint32_t streamID
Definition: SPDYCodec.cpp:131
size_t generatePingRequest(folly::IOBufQueue &writeBuf) override
Definition: SPDYCodec.cpp:917
TEST(SequencedExecutor, CPUThreadPoolExecutor)
uint8_t invalidHeaderPlusEmptyBlock[]
ErrorCode rstToErrorCode(uint32_t code)
const uint8_t kColonHeaders[]
const HTTPSetting * getSetting(SettingsId id) const
size_t generateGoaway(folly::IOBufQueue &writeBuf, StreamID lastStream, ErrorCode statusCode, std::unique_ptr< folly::IOBuf > debugData=nullptr) override
Definition: SPDYCodec.cpp:856
#define EXPECT_GT(val1, val2)
Definition: gtest.h:1934
void setSetting(SettingsId id, SettingsValue val)
uint8_t shortSynStream[]
void setStatusCode(uint16_t status)
void setMaxUncompressedHeaders(uint32_t maxUncompressed)
Definition: SPDYCodec.cpp:193