Home | History | Annotate | Download | only in flip
      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 
     18 void FramerSetEnableCompressionHelper(FlipFramer* framer, bool compress) {
     19   framer->set_enable_compression(compress);
     20 }
     21 
     22 class TestFlipVisitor : public FlipFramerVisitorInterface  {
     23  public:
     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 
     34   void OnError(FlipFramer* f) {
     35     error_count_++;
     36   }
     37 
     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 
     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.
     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:
    130   virtual void TearDown() {}
    131 };
    132 
    133 // Test that we can encode and decode a FlipHeaderBlock.
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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.
    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