• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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