1 // Copyright (c) 2009 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 #include <algorithm>
6 #include <iostream>
7
8 #include "base/scoped_ptr.h"
9 #include "flip_framer.h" // cross-google3 directory naming.
10 #include "flip_protocol.h"
11 #include "flip_frame_builder.h"
12 #include "testing/platform_test.h"
13
14 namespace flip {
15
16 namespace test {
17
FramerSetEnableCompressionHelper(FlipFramer * framer,bool compress)18 void FramerSetEnableCompressionHelper(FlipFramer* framer, bool compress) {
19 framer->set_enable_compression(compress);
20 }
21
22 class TestFlipVisitor : public FlipFramerVisitorInterface {
23 public:
TestFlipVisitor()24 TestFlipVisitor()
25 : error_count_(0),
26 syn_frame_count_(0),
27 syn_reply_frame_count_(0),
28 data_bytes_(0),
29 fin_frame_count_(0),
30 fin_flag_count_(0),
31 zero_length_data_frame_count_(0) {
32 }
33
OnError(FlipFramer * f)34 void OnError(FlipFramer* f) {
35 error_count_++;
36 }
37
OnStreamFrameData(FlipStreamId stream_id,const char * data,size_t len)38 void OnStreamFrameData(FlipStreamId stream_id,
39 const char* data,
40 size_t len) {
41 if (len == 0)
42 ++zero_length_data_frame_count_;
43
44 data_bytes_ += len;
45 std::cerr << "OnStreamFrameData(" << stream_id << ", \"";
46 if (len > 0) {
47 for (size_t i = 0 ; i < len; ++i) {
48 std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec;
49 }
50 }
51 std::cerr << "\", " << len << ")\n";
52 }
53
OnControl(const FlipControlFrame * frame)54 void OnControl(const FlipControlFrame* frame) {
55 FlipHeaderBlock headers;
56 bool parsed_headers = false;
57 switch (frame->type()) {
58 case SYN_STREAM:
59 parsed_headers = framer_.ParseHeaderBlock(frame, &headers);
60 DCHECK(parsed_headers);
61 syn_frame_count_++;
62 break;
63 case SYN_REPLY:
64 parsed_headers = framer_.ParseHeaderBlock(frame, &headers);
65 DCHECK(parsed_headers);
66 syn_reply_frame_count_++;
67 break;
68 case FIN_STREAM:
69 fin_frame_count_++;
70 break;
71 default:
72 DCHECK(false); // Error!
73 }
74 if (frame->flags() & CONTROL_FLAG_FIN)
75 ++fin_flag_count_;
76 }
77
78 // Convenience function which runs a framer simulation with particular input.
SimulateInFramer(const unsigned char * input,size_t size)79 void SimulateInFramer(const unsigned char* input, size_t size) {
80 framer_.set_enable_compression(false);
81 framer_.set_visitor(this);
82 size_t input_remaining = size;
83 const char* input_ptr = reinterpret_cast<const char*>(input);
84 while (input_remaining > 0 &&
85 framer_.error_code() == FlipFramer::FLIP_NO_ERROR) {
86 // To make the tests more interesting, we feed random (amd small) chunks
87 // into the framer. This simulates getting strange-sized reads from
88 // the socket.
89 const size_t kMaxReadSize = 32;
90 size_t bytes_read =
91 (rand() % std::min(input_remaining, kMaxReadSize)) + 1;
92 size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read);
93 input_remaining -= bytes_processed;
94 input_ptr += bytes_processed;
95 if (framer_.state() == FlipFramer::FLIP_DONE)
96 framer_.Reset();
97 }
98 }
99
100 FlipFramer framer_;
101 // Counters from the visitor callbacks.
102 int error_count_;
103 int syn_frame_count_;
104 int syn_reply_frame_count_;
105 int data_bytes_;
106 int fin_frame_count_; // The count of FIN_STREAM type frames received.
107 int fin_flag_count_; // The count of frames with the FIN flag set.
108 int zero_length_data_frame_count_; // The count of zero-length data frames.
109 };
110
111 } // namespace test
112
113 } // namespace flip
114
115 using flip::FlipFrame;
116 using flip::FlipFrameBuilder;
117 using flip::FlipFramer;
118 using flip::FlipHeaderBlock;
119 using flip::FlipSynStreamControlFrame;
120 using flip::kControlFlagMask;
121 using flip::CONTROL_FLAG_NONE;
122 using flip::SYN_STREAM;
123 using flip::test::FramerSetEnableCompressionHelper;
124 using flip::test::TestFlipVisitor;
125
126 namespace {
127
128 class FlipFramerTest : public PlatformTest {
129 public:
TearDown()130 virtual void TearDown() {}
131 };
132
133 // Test that we can encode and decode a FlipHeaderBlock.
TEST_F(FlipFramerTest,HeaderBlock)134 TEST_F(FlipFramerTest, HeaderBlock) {
135 FlipHeaderBlock headers;
136 headers["alpha"] = "beta";
137 headers["gamma"] = "charlie";
138 FlipFramer framer;
139
140 // Encode the header block into a SynStream frame.
141 scoped_ptr<FlipSynStreamControlFrame> frame(
142 framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers));
143 EXPECT_TRUE(frame.get() != NULL);
144
145 FlipHeaderBlock new_headers;
146 framer.ParseHeaderBlock(frame.get(), &new_headers);
147
148 EXPECT_EQ(headers.size(), new_headers.size());
149 EXPECT_EQ(headers["alpha"], new_headers["alpha"]);
150 EXPECT_EQ(headers["gamma"], new_headers["gamma"]);
151 }
152
TEST_F(FlipFramerTest,OutOfOrderHeaders)153 TEST_F(FlipFramerTest, OutOfOrderHeaders) {
154 FlipFrameBuilder frame;
155
156 frame.WriteUInt16(kControlFlagMask | 1);
157 frame.WriteUInt16(SYN_STREAM);
158 frame.WriteUInt32(0); // Placeholder for the length.
159 frame.WriteUInt32(3); // stream_id
160 frame.WriteUInt16(0); // Priority.
161
162 frame.WriteUInt16(2); // Number of headers.
163 FlipHeaderBlock::iterator it;
164 frame.WriteString("gamma");
165 frame.WriteString("gamma");
166 frame.WriteString("alpha");
167 frame.WriteString("alpha");
168 // write the length
169 frame.WriteUInt32ToOffset(4, frame.length() - FlipFrame::size());
170
171 FlipHeaderBlock new_headers;
172 scoped_ptr<FlipFrame> control_frame(frame.take());
173 FlipFramer framer;
174 FramerSetEnableCompressionHelper(&framer, false);
175 EXPECT_TRUE(framer.ParseHeaderBlock(control_frame.get(), &new_headers));
176 }
177
TEST_F(FlipFramerTest,DuplicateHeader)178 TEST_F(FlipFramerTest, DuplicateHeader) {
179 FlipFrameBuilder frame;
180
181 frame.WriteUInt16(kControlFlagMask | 1);
182 frame.WriteUInt16(SYN_STREAM);
183 frame.WriteUInt32(0); // Placeholder for the length.
184 frame.WriteUInt32(3); // stream_id
185 frame.WriteUInt16(0); // Priority.
186
187 frame.WriteUInt16(2); // Number of headers.
188 FlipHeaderBlock::iterator it;
189 frame.WriteString("name");
190 frame.WriteString("value1");
191 frame.WriteString("name");
192 frame.WriteString("value2");
193 // write the length
194 frame.WriteUInt32ToOffset(4, frame.length() - FlipFrame::size());
195
196 FlipHeaderBlock new_headers;
197 scoped_ptr<FlipFrame> control_frame(frame.take());
198 FlipFramer framer;
199 FramerSetEnableCompressionHelper(&framer, false);
200 // This should fail because duplicate headers are verboten by the spec.
201 EXPECT_FALSE(framer.ParseHeaderBlock(control_frame.get(), &new_headers));
202 }
203
TEST_F(FlipFramerTest,MultiValueHeader)204 TEST_F(FlipFramerTest, MultiValueHeader) {
205 FlipFrameBuilder frame;
206
207 frame.WriteUInt16(kControlFlagMask | 1);
208 frame.WriteUInt16(SYN_STREAM);
209 frame.WriteUInt32(0); // Placeholder for the length.
210 frame.WriteUInt32(3); // stream_id
211 frame.WriteUInt16(0); // Priority.
212
213 frame.WriteUInt16(2); // Number of headers.
214 FlipHeaderBlock::iterator it;
215 frame.WriteString("name");
216 std::string value("value1\0value2");
217 frame.WriteString(value);
218 // write the length
219 frame.WriteUInt32ToOffset(4, frame.length() - FlipFrame::size());
220
221 FlipHeaderBlock new_headers;
222 scoped_ptr<FlipFrame> control_frame(frame.take());
223 FlipFramer framer;
224 FramerSetEnableCompressionHelper(&framer, false);
225 EXPECT_TRUE(framer.ParseHeaderBlock(control_frame.get(), &new_headers));
226 EXPECT_TRUE(new_headers.find("name") != new_headers.end());
227 EXPECT_EQ(value, new_headers.find("name")->second);
228 }
229
TEST_F(FlipFramerTest,BasicCompression)230 TEST_F(FlipFramerTest, BasicCompression) {
231 FlipHeaderBlock headers;
232 headers["server"] = "FlipServer 1.0";
233 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST";
234 headers["status"] = "200";
235 headers["version"] = "HTTP/1.1";
236 headers["content-type"] = "text/html";
237 headers["content-length"] = "12";
238
239 FlipFramer framer;
240 FramerSetEnableCompressionHelper(&framer, true);
241 scoped_ptr<FlipSynStreamControlFrame>
242 frame1(framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers));
243 scoped_ptr<FlipSynStreamControlFrame>
244 frame2(framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers));
245
246 // Expect the second frame to be more compact than the first.
247 EXPECT_LE(frame2->length(), frame1->length());
248
249 // Decompress the first frame
250 scoped_ptr<FlipFrame> frame3(framer.DecompressFrame(frame1.get()));
251
252 // Decompress the second frame
253 scoped_ptr<FlipFrame> frame4(framer.DecompressFrame(frame2.get()));
254
255 // Expect frames 3 & 4 to be the same.
256 EXPECT_EQ(0,
257 memcmp(frame3->data(), frame4->data(),
258 FlipFrame::size() + frame3->length()));
259 }
260
TEST_F(FlipFramerTest,DecompressUncompressedFrame)261 TEST_F(FlipFramerTest, DecompressUncompressedFrame) {
262 FlipHeaderBlock headers;
263 headers["server"] = "FlipServer 1.0";
264 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST";
265 headers["status"] = "200";
266 headers["version"] = "HTTP/1.1";
267 headers["content-type"] = "text/html";
268 headers["content-length"] = "12";
269
270 FlipFramer framer;
271 FramerSetEnableCompressionHelper(&framer, true);
272 scoped_ptr<FlipSynStreamControlFrame>
273 frame1(framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, false, &headers));
274
275 // Decompress the frame
276 scoped_ptr<FlipFrame> frame2(framer.DecompressFrame(frame1.get()));
277
278 EXPECT_EQ(NULL, frame2.get());
279 }
280
TEST_F(FlipFramerTest,Basic)281 TEST_F(FlipFramerTest, Basic) {
282 const unsigned char input[] = {
283 0x80, 0x01, 0x00, 0x01, // SYN Stream #1
284 0x00, 0x00, 0x00, 0x10,
285 0x00, 0x00, 0x00, 0x01,
286 0x00, 0x00, 0x00, 0x01,
287 0x00, 0x02, 'h', 'h',
288 0x00, 0x02, 'v', 'v',
289
290 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
291 0x00, 0x00, 0x00, 0x0c,
292 0xde, 0xad, 0xbe, 0xef,
293 0xde, 0xad, 0xbe, 0xef,
294 0xde, 0xad, 0xbe, 0xef,
295
296 0x80, 0x01, 0x00, 0x01, // SYN Stream #3
297 0x00, 0x00, 0x00, 0x08,
298 0x00, 0x00, 0x00, 0x03,
299 0x00, 0x00, 0x00, 0x00,
300
301 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
302 0x00, 0x00, 0x00, 0x08,
303 0xde, 0xad, 0xbe, 0xef,
304 0xde, 0xad, 0xbe, 0xef,
305
306 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
307 0x00, 0x00, 0x00, 0x04,
308 0xde, 0xad, 0xbe, 0xef,
309
310 0x80, 0x01, 0x00, 0x03, // FIN on Stream #1
311 0x00, 0x00, 0x00, 0x08,
312 0x00, 0x00, 0x00, 0x01,
313 0x00, 0x00, 0x00, 0x00,
314
315 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
316 0x00, 0x00, 0x00, 0x00,
317
318 0x80, 0x01, 0x00, 0x03, // FIN on Stream #3
319 0x00, 0x00, 0x00, 0x08,
320 0x00, 0x00, 0x00, 0x03,
321 0x00, 0x00, 0x00, 0x00,
322 };
323
324 TestFlipVisitor visitor;
325 visitor.SimulateInFramer(input, sizeof(input));
326
327 EXPECT_EQ(0, visitor.error_count_);
328 EXPECT_EQ(2, visitor.syn_frame_count_);
329 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
330 EXPECT_EQ(24, visitor.data_bytes_);
331 EXPECT_EQ(2, visitor.fin_frame_count_);
332 EXPECT_EQ(0, visitor.fin_flag_count_);
333 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
334 }
335
336 // Test that the FIN flag on a data frame signifies EOF.
TEST_F(FlipFramerTest,FinOnDataFrame)337 TEST_F(FlipFramerTest, FinOnDataFrame) {
338 const unsigned char input[] = {
339 0x80, 0x01, 0x00, 0x01, // SYN Stream #1
340 0x00, 0x00, 0x00, 0x10,
341 0x00, 0x00, 0x00, 0x01,
342 0x00, 0x00, 0x00, 0x01,
343 0x00, 0x02, 'h', 'h',
344 0x00, 0x02, 'v', 'v',
345
346 0x80, 0x01, 0x00, 0x02, // SYN REPLY Stream #1
347 0x00, 0x00, 0x00, 0x10,
348 0x00, 0x00, 0x00, 0x01,
349 0x00, 0x00, 0x00, 0x01,
350 0x00, 0x02, 'a', 'a',
351 0x00, 0x02, 'b', 'b',
352
353 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
354 0x00, 0x00, 0x00, 0x0c,
355 0xde, 0xad, 0xbe, 0xef,
356 0xde, 0xad, 0xbe, 0xef,
357 0xde, 0xad, 0xbe, 0xef,
358
359 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF
360 0x01, 0x00, 0x00, 0x04,
361 0xde, 0xad, 0xbe, 0xef,
362 };
363
364 TestFlipVisitor visitor;
365 visitor.SimulateInFramer(input, sizeof(input));
366
367 EXPECT_EQ(0, visitor.error_count_);
368 EXPECT_EQ(1, visitor.syn_frame_count_);
369 EXPECT_EQ(1, visitor.syn_reply_frame_count_);
370 EXPECT_EQ(16, visitor.data_bytes_);
371 EXPECT_EQ(0, visitor.fin_frame_count_);
372 EXPECT_EQ(0, visitor.fin_flag_count_);
373 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
374 }
375
376 // Test that the FIN flag on a SYN reply frame signifies EOF.
TEST_F(FlipFramerTest,FinOnSynReplyFrame)377 TEST_F(FlipFramerTest, FinOnSynReplyFrame) {
378 const unsigned char input[] = {
379 0x80, 0x01, 0x00, 0x01, // SYN Stream #1
380 0x00, 0x00, 0x00, 0x10,
381 0x00, 0x00, 0x00, 0x01,
382 0x00, 0x00, 0x00, 0x01,
383 0x00, 0x02, 'h', 'h',
384 0x00, 0x02, 'v', 'v',
385
386 0x80, 0x01, 0x00, 0x02, // SYN REPLY Stream #1
387 0x01, 0x00, 0x00, 0x10,
388 0x00, 0x00, 0x00, 0x01,
389 0x00, 0x00, 0x00, 0x01,
390 0x00, 0x02, 'a', 'a',
391 0x00, 0x02, 'b', 'b',
392 };
393
394 TestFlipVisitor visitor;
395 visitor.SimulateInFramer(input, sizeof(input));
396
397 EXPECT_EQ(0, visitor.error_count_);
398 EXPECT_EQ(1, visitor.syn_frame_count_);
399 EXPECT_EQ(1, visitor.syn_reply_frame_count_);
400 EXPECT_EQ(0, visitor.data_bytes_);
401 EXPECT_EQ(0, visitor.fin_frame_count_);
402 EXPECT_EQ(1, visitor.fin_flag_count_);
403 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
404 }
405
406 } // namespace
407
408