Home | History | Annotate | Download | only in spdy
      1 // Copyright (c) 2011 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/memory/scoped_ptr.h"
      9 #include "net/spdy/spdy_framer.h"
     10 #include "net/spdy/spdy_protocol.h"
     11 #include "net/spdy/spdy_frame_builder.h"
     12 #include "testing/platform_test.h"
     13 
     14 namespace spdy {
     15 
     16 namespace test {
     17 
     18 std::string HexDumpWithMarks(const unsigned char* data, int length,
     19                              const bool* marks, int mark_length) {
     20   static const char kHexChars[] = "0123456789ABCDEF";
     21   static const int kColumns = 4;
     22 
     23   std::string hex;
     24   for (const unsigned char* row = data; length > 0;
     25        row += kColumns, length -= kColumns) {
     26     for (const unsigned char *p = row; p < row + 4; ++p) {
     27       if (p < row + length) {
     28         const bool mark =
     29             (marks && (p - data) < mark_length && marks[p - data]);
     30         hex += mark ? '*' : ' ';
     31         hex += kHexChars[(*p & 0xf0) >> 4];
     32         hex += kHexChars[*p & 0x0f];
     33         hex += mark ? '*' : ' ';
     34       } else {
     35         hex += "    ";
     36       }
     37     }
     38     hex = hex + "  ";
     39 
     40     for (const unsigned char *p = row; p < row + 4 && p < row + length; ++p)
     41       hex += (*p >= 0x20 && *p <= 0x7f) ? (*p) : '.';
     42 
     43     hex = hex + '\n';
     44   }
     45   return hex;
     46 }
     47 
     48 void CompareCharArraysWithHexError(
     49     const std::string& description,
     50     const unsigned char* actual,
     51     const int actual_len,
     52     const unsigned char* expected,
     53     const int expected_len) {
     54   const int min_len = actual_len > expected_len ? expected_len : actual_len;
     55   const int max_len = actual_len > expected_len ? actual_len : expected_len;
     56   scoped_array<bool> marks(new bool[max_len]);
     57   bool identical = (actual_len == expected_len);
     58   for (int i = 0; i < min_len; ++i) {
     59     if (actual[i] != expected[i]) {
     60       marks[i] = true;
     61       identical = false;
     62     } else {
     63       marks[i] = false;
     64     }
     65   }
     66   for (int i = min_len; i < max_len; ++i) {
     67     marks[i] = true;
     68   }
     69   if (identical) return;
     70   ADD_FAILURE()
     71       << "Description:\n"
     72       << description
     73       << "\n\nExpected:\n"
     74       << HexDumpWithMarks(expected, expected_len, marks.get(), max_len)
     75       << "\nActual:\n"
     76       << HexDumpWithMarks(actual, actual_len, marks.get(), max_len);
     77 }
     78 
     79 void FramerSetEnableCompressionHelper(SpdyFramer* framer, bool compress) {
     80   framer->set_enable_compression(compress);
     81 }
     82 
     83 class TestSpdyVisitor : public SpdyFramerVisitorInterface  {
     84  public:
     85   TestSpdyVisitor()
     86     : error_count_(0),
     87       syn_frame_count_(0),
     88       syn_reply_frame_count_(0),
     89       headers_frame_count_(0),
     90       data_bytes_(0),
     91       fin_frame_count_(0),
     92       fin_flag_count_(0),
     93       zero_length_data_frame_count_(0) {
     94   }
     95 
     96   void OnError(SpdyFramer* f) {
     97     error_count_++;
     98   }
     99 
    100   void OnStreamFrameData(SpdyStreamId stream_id,
    101                          const char* data,
    102                          size_t len) {
    103     if (len == 0)
    104       ++zero_length_data_frame_count_;
    105 
    106     data_bytes_ += len;
    107     std::cerr << "OnStreamFrameData(" << stream_id << ", \"";
    108     if (len > 0) {
    109       for (size_t i = 0 ; i < len; ++i) {
    110         std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec;
    111       }
    112     }
    113     std::cerr << "\", " << len << ")\n";
    114   }
    115 
    116   void OnControl(const SpdyControlFrame* frame) {
    117     SpdyHeaderBlock headers;
    118     bool parsed_headers = false;
    119     switch (frame->type()) {
    120       case SYN_STREAM:
    121         parsed_headers = framer_.ParseHeaderBlock(frame, &headers);
    122         DCHECK(parsed_headers);
    123         syn_frame_count_++;
    124         break;
    125       case SYN_REPLY:
    126         parsed_headers = framer_.ParseHeaderBlock(frame, &headers);
    127         DCHECK(parsed_headers);
    128         syn_reply_frame_count_++;
    129         break;
    130       case RST_STREAM:
    131         fin_frame_count_++;
    132         break;
    133       case HEADERS:
    134         parsed_headers = framer_.ParseHeaderBlock(frame, &headers);
    135         DCHECK(parsed_headers);
    136         headers_frame_count_++;
    137         break;
    138       default:
    139         DCHECK(false);  // Error!
    140     }
    141     if (frame->flags() & CONTROL_FLAG_FIN)
    142       ++fin_flag_count_;
    143   }
    144 
    145   bool OnControlFrameHeaderData(SpdyStreamId stream_id,
    146                                 const char* header_data,
    147                                 size_t len) {
    148     DCHECK(false);
    149     return false;
    150   }
    151 
    152   void OnDataFrameHeader(const SpdyDataFrame* frame) {
    153     DCHECK(false);
    154   }
    155 
    156   // Convenience function which runs a framer simulation with particular input.
    157   void SimulateInFramer(const unsigned char* input, size_t size) {
    158     framer_.set_enable_compression(false);
    159     framer_.set_visitor(this);
    160     size_t input_remaining = size;
    161     const char* input_ptr = reinterpret_cast<const char*>(input);
    162     while (input_remaining > 0 &&
    163            framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) {
    164       // To make the tests more interesting, we feed random (amd small) chunks
    165       // into the framer.  This simulates getting strange-sized reads from
    166       // the socket.
    167       const size_t kMaxReadSize = 32;
    168       size_t bytes_read =
    169           (rand() % std::min(input_remaining, kMaxReadSize)) + 1;
    170       size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read);
    171       input_remaining -= bytes_processed;
    172       input_ptr += bytes_processed;
    173       if (framer_.state() == SpdyFramer::SPDY_DONE)
    174         framer_.Reset();
    175     }
    176   }
    177 
    178   SpdyFramer framer_;
    179   // Counters from the visitor callbacks.
    180   int error_count_;
    181   int syn_frame_count_;
    182   int syn_reply_frame_count_;
    183   int headers_frame_count_;
    184   int data_bytes_;
    185   int fin_frame_count_;  // The count of RST_STREAM type frames received.
    186   int fin_flag_count_;  // The count of frames with the FIN flag set.
    187   int zero_length_data_frame_count_;  // The count of zero-length data frames.
    188 };
    189 
    190 }  // namespace test
    191 
    192 }  // namespace spdy
    193 
    194 using spdy::SpdyControlFlags;
    195 using spdy::SpdyControlFrame;
    196 using spdy::SpdyDataFrame;
    197 using spdy::SpdyFrame;
    198 using spdy::SpdyFrameBuilder;
    199 using spdy::SpdyFramer;
    200 using spdy::SpdyHeaderBlock;
    201 using spdy::SpdySynStreamControlFrame;
    202 using spdy::kControlFlagMask;
    203 using spdy::CONTROL_FLAG_NONE;
    204 using spdy::DATA_FLAG_COMPRESSED;
    205 using spdy::DATA_FLAG_FIN;
    206 using spdy::SYN_STREAM;
    207 using spdy::test::CompareCharArraysWithHexError;
    208 using spdy::test::FramerSetEnableCompressionHelper;
    209 using spdy::test::TestSpdyVisitor;
    210 
    211 namespace spdy {
    212 
    213 class SpdyFramerTest : public PlatformTest {
    214  public:
    215   virtual void TearDown() {}
    216 
    217  protected:
    218   void CompareFrame(const std::string& description,
    219                     const SpdyFrame& actual_frame,
    220                     const unsigned char* expected,
    221                     const int expected_len) {
    222     const unsigned char* actual =
    223         reinterpret_cast<const unsigned char*>(actual_frame.data());
    224     int actual_len = actual_frame.length() + SpdyFrame::size();
    225     CompareCharArraysWithHexError(
    226         description, actual, actual_len, expected, expected_len);
    227   }
    228 };
    229 
    230 // Test that we can encode and decode a SpdyHeaderBlock.
    231 TEST_F(SpdyFramerTest, HeaderBlock) {
    232   SpdyHeaderBlock headers;
    233   headers["alpha"] = "beta";
    234   headers["gamma"] = "charlie";
    235   SpdyFramer framer;
    236 
    237   // Encode the header block into a SynStream frame.
    238   scoped_ptr<SpdySynStreamControlFrame> frame(
    239       framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, &headers));
    240   EXPECT_TRUE(frame.get() != NULL);
    241 
    242   SpdyHeaderBlock new_headers;
    243   EXPECT_TRUE(framer.ParseHeaderBlock(frame.get(), &new_headers));
    244 
    245   EXPECT_EQ(headers.size(), new_headers.size());
    246   EXPECT_EQ(headers["alpha"], new_headers["alpha"]);
    247   EXPECT_EQ(headers["gamma"], new_headers["gamma"]);
    248 }
    249 
    250 TEST_F(SpdyFramerTest, OutOfOrderHeaders) {
    251   SpdyFrameBuilder frame;
    252 
    253   frame.WriteUInt16(kControlFlagMask | 1);
    254   frame.WriteUInt16(SYN_STREAM);
    255   frame.WriteUInt32(0);  // Placeholder for the length.
    256   frame.WriteUInt32(3);  // stream_id
    257   frame.WriteUInt32(0);  // associated stream id
    258   frame.WriteUInt16(0);  // Priority.
    259 
    260   frame.WriteUInt16(2);  // Number of headers.
    261   SpdyHeaderBlock::iterator it;
    262   frame.WriteString("gamma");
    263   frame.WriteString("gamma");
    264   frame.WriteString("alpha");
    265   frame.WriteString("alpha");
    266   // write the length
    267   frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::size());
    268 
    269   SpdyHeaderBlock new_headers;
    270   scoped_ptr<SpdyFrame> control_frame(frame.take());
    271   SpdyFramer framer;
    272   FramerSetEnableCompressionHelper(&framer, false);
    273   EXPECT_TRUE(framer.ParseHeaderBlock(control_frame.get(), &new_headers));
    274 }
    275 
    276 TEST_F(SpdyFramerTest, WrongNumberOfHeaders) {
    277   SpdyFrameBuilder frame1;
    278   SpdyFrameBuilder frame2;
    279 
    280   // a frame with smaller number of actual headers
    281   frame1.WriteUInt16(kControlFlagMask | 1);
    282   frame1.WriteUInt16(SYN_STREAM);
    283   frame1.WriteUInt32(0);  // Placeholder for the length.
    284   frame1.WriteUInt32(3);  // stream_id
    285   frame1.WriteUInt16(0);  // Priority.
    286 
    287   frame1.WriteUInt16(1);  // Wrong number of headers (underflow)
    288   frame1.WriteString("gamma");
    289   frame1.WriteString("gamma");
    290   frame1.WriteString("alpha");
    291   frame1.WriteString("alpha");
    292   // write the length
    293   frame1.WriteUInt32ToOffset(4, frame1.length() - SpdyFrame::size());
    294 
    295   // a frame with larger number of actual headers
    296   frame2.WriteUInt16(kControlFlagMask | 1);
    297   frame2.WriteUInt16(SYN_STREAM);
    298   frame2.WriteUInt32(0);  // Placeholder for the length.
    299   frame2.WriteUInt32(3);  // stream_id
    300   frame2.WriteUInt16(0);  // Priority.
    301 
    302   frame2.WriteUInt16(100);  // Wrong number of headers (overflow)
    303   frame2.WriteString("gamma");
    304   frame2.WriteString("gamma");
    305   frame2.WriteString("alpha");
    306   frame2.WriteString("alpha");
    307   // write the length
    308   frame2.WriteUInt32ToOffset(4, frame2.length() - SpdyFrame::size());
    309 
    310   SpdyHeaderBlock new_headers;
    311   scoped_ptr<SpdyFrame> syn_frame1(frame1.take());
    312   scoped_ptr<SpdyFrame> syn_frame2(frame2.take());
    313   SpdyFramer framer;
    314   FramerSetEnableCompressionHelper(&framer, false);
    315   EXPECT_FALSE(framer.ParseHeaderBlock(syn_frame1.get(), &new_headers));
    316   EXPECT_FALSE(framer.ParseHeaderBlock(syn_frame2.get(), &new_headers));
    317 }
    318 
    319 TEST_F(SpdyFramerTest, DuplicateHeader) {
    320   SpdyFrameBuilder frame;
    321 
    322   frame.WriteUInt16(kControlFlagMask | 1);
    323   frame.WriteUInt16(SYN_STREAM);
    324   frame.WriteUInt32(0);  // Placeholder for the length.
    325   frame.WriteUInt32(3);  // stream_id
    326   frame.WriteUInt32(0);  // associated stream id
    327   frame.WriteUInt16(0);  // Priority.
    328 
    329   frame.WriteUInt16(2);  // Number of headers.
    330   SpdyHeaderBlock::iterator it;
    331   frame.WriteString("name");
    332   frame.WriteString("value1");
    333   frame.WriteString("name");
    334   frame.WriteString("value2");
    335   // write the length
    336   frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::size());
    337 
    338   SpdyHeaderBlock new_headers;
    339   scoped_ptr<SpdyFrame> control_frame(frame.take());
    340   SpdyFramer framer;
    341   FramerSetEnableCompressionHelper(&framer, false);
    342   // This should fail because duplicate headers are verboten by the spec.
    343   EXPECT_FALSE(framer.ParseHeaderBlock(control_frame.get(), &new_headers));
    344 }
    345 
    346 TEST_F(SpdyFramerTest, MultiValueHeader) {
    347   SpdyFrameBuilder frame;
    348 
    349   frame.WriteUInt16(kControlFlagMask | 1);
    350   frame.WriteUInt16(SYN_STREAM);
    351   frame.WriteUInt32(0);  // Placeholder for the length.
    352   frame.WriteUInt32(3);  // stream_id
    353   frame.WriteUInt32(0);  // associated stream id
    354   frame.WriteUInt16(0);  // Priority.
    355 
    356   frame.WriteUInt16(1);  // Number of headers.
    357   SpdyHeaderBlock::iterator it;
    358   frame.WriteString("name");
    359   std::string value("value1\0value2");
    360   frame.WriteString(value);
    361   // write the length
    362   frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::size());
    363 
    364   SpdyHeaderBlock new_headers;
    365   scoped_ptr<SpdyFrame> control_frame(frame.take());
    366   SpdyFramer framer;
    367   FramerSetEnableCompressionHelper(&framer, false);
    368   EXPECT_TRUE(framer.ParseHeaderBlock(control_frame.get(), &new_headers));
    369   EXPECT_TRUE(new_headers.find("name") != new_headers.end());
    370   EXPECT_EQ(value, new_headers.find("name")->second);
    371 }
    372 
    373 TEST_F(SpdyFramerTest, ZeroLengthHeader) {
    374   SpdyHeaderBlock header1;
    375   SpdyHeaderBlock header2;
    376   SpdyHeaderBlock header3;
    377 
    378   header1[""] = "value2";
    379   header2["name3"] = "";
    380   header3[""] = "";
    381 
    382   SpdyFramer framer;
    383   SpdyHeaderBlock parsed_headers;
    384 
    385   scoped_ptr<SpdySynStreamControlFrame> frame1(
    386       framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, &header1));
    387   EXPECT_TRUE(frame1.get() != NULL);
    388   EXPECT_FALSE(framer.ParseHeaderBlock(frame1.get(), &parsed_headers));
    389 
    390   scoped_ptr<SpdySynStreamControlFrame> frame2(
    391       framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, &header2));
    392   EXPECT_TRUE(frame2.get() != NULL);
    393   EXPECT_FALSE(framer.ParseHeaderBlock(frame2.get(), &parsed_headers));
    394 
    395   scoped_ptr<SpdySynStreamControlFrame> frame3(
    396       framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, &header3));
    397   EXPECT_TRUE(frame3.get() != NULL);
    398   EXPECT_FALSE(framer.ParseHeaderBlock(frame3.get(), &parsed_headers));
    399 }
    400 
    401 TEST_F(SpdyFramerTest, BasicCompression) {
    402   SpdyHeaderBlock headers;
    403   headers["server"] = "SpdyServer 1.0";
    404   headers["date"] = "Mon 12 Jan 2009 12:12:12 PST";
    405   headers["status"] = "200";
    406   headers["version"] = "HTTP/1.1";
    407   headers["content-type"] = "text/html";
    408   headers["content-length"] = "12";
    409 
    410   SpdyFramer framer;
    411   FramerSetEnableCompressionHelper(&framer, true);
    412   scoped_ptr<SpdySynStreamControlFrame>
    413       frame1(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true,
    414                                     &headers));
    415   scoped_ptr<SpdySynStreamControlFrame>
    416       frame2(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true,
    417                                     &headers));
    418 
    419   // Expect the second frame to be more compact than the first.
    420   EXPECT_LE(frame2->length(), frame1->length());
    421 
    422   // Decompress the first frame
    423   scoped_ptr<SpdyFrame> frame3(framer.DecompressFrame(*frame1.get()));
    424 
    425   // Decompress the second frame
    426   scoped_ptr<SpdyFrame> frame4(framer.DecompressFrame(*frame2.get()));
    427 
    428   // Expect frames 3 & 4 to be the same.
    429   EXPECT_EQ(0,
    430       memcmp(frame3->data(), frame4->data(),
    431       SpdyFrame::size() + frame3->length()));
    432 }
    433 
    434 TEST_F(SpdyFramerTest, DecompressUncompressedFrame) {
    435   SpdyHeaderBlock headers;
    436   headers["server"] = "SpdyServer 1.0";
    437   headers["date"] = "Mon 12 Jan 2009 12:12:12 PST";
    438   headers["status"] = "200";
    439   headers["version"] = "HTTP/1.1";
    440   headers["content-type"] = "text/html";
    441   headers["content-length"] = "12";
    442 
    443   SpdyFramer framer;
    444   FramerSetEnableCompressionHelper(&framer, true);
    445   scoped_ptr<SpdySynStreamControlFrame>
    446       frame1(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false,
    447                                     &headers));
    448 
    449   // Decompress the frame
    450   scoped_ptr<SpdyFrame> frame2(framer.DecompressFrame(*frame1.get()));
    451 
    452   EXPECT_EQ(NULL, frame2.get());
    453 }
    454 
    455 TEST_F(SpdyFramerTest, Basic) {
    456   const unsigned char input[] = {
    457     0x80, 0x02, 0x00, 0x01,   // SYN Stream #1
    458     0x00, 0x00, 0x00, 0x14,
    459     0x00, 0x00, 0x00, 0x01,
    460     0x00, 0x00, 0x00, 0x00,
    461     0x00, 0x00, 0x00, 0x01,
    462     0x00, 0x02, 'h', 'h',
    463     0x00, 0x02, 'v', 'v',
    464 
    465     0x80, 0x02, 0x00, 0x08,   // HEADERS on Stream #1
    466     0x00, 0x00, 0x00, 0x18,
    467     0x00, 0x00, 0x00, 0x01,
    468     0x00, 0x00, 0x00, 0x02,
    469     0x00, 0x02, 'h', '2',
    470     0x00, 0x02, 'v', '2',
    471     0x00, 0x02, 'h', '3',
    472     0x00, 0x02, 'v', '3',
    473 
    474     0x00, 0x00, 0x00, 0x01,   // DATA on Stream #1
    475     0x00, 0x00, 0x00, 0x0c,
    476       0xde, 0xad, 0xbe, 0xef,
    477       0xde, 0xad, 0xbe, 0xef,
    478       0xde, 0xad, 0xbe, 0xef,
    479 
    480     0x80, 0x02, 0x00, 0x01,   // SYN Stream #3
    481     0x00, 0x00, 0x00, 0x0c,
    482     0x00, 0x00, 0x00, 0x03,
    483     0x00, 0x00, 0x00, 0x00,
    484     0x00, 0x00, 0x00, 0x00,
    485 
    486     0x00, 0x00, 0x00, 0x03,   // DATA on Stream #3
    487     0x00, 0x00, 0x00, 0x08,
    488       0xde, 0xad, 0xbe, 0xef,
    489       0xde, 0xad, 0xbe, 0xef,
    490 
    491     0x00, 0x00, 0x00, 0x01,   // DATA on Stream #1
    492     0x00, 0x00, 0x00, 0x04,
    493       0xde, 0xad, 0xbe, 0xef,
    494 
    495     0x80, 0x02, 0x00, 0x03,   // RST_STREAM on Stream #1
    496     0x00, 0x00, 0x00, 0x08,
    497     0x00, 0x00, 0x00, 0x01,
    498     0x00, 0x00, 0x00, 0x00,
    499 
    500     0x00, 0x00, 0x00, 0x03,   // DATA on Stream #3
    501     0x00, 0x00, 0x00, 0x00,
    502 
    503     0x80, 0x02, 0x00, 0x03,   // RST_STREAM on Stream #3
    504     0x00, 0x00, 0x00, 0x08,
    505     0x00, 0x00, 0x00, 0x03,
    506     0x00, 0x00, 0x00, 0x00,
    507   };
    508 
    509   TestSpdyVisitor visitor;
    510   visitor.SimulateInFramer(input, sizeof(input));
    511 
    512   EXPECT_EQ(0, visitor.error_count_);
    513   EXPECT_EQ(2, visitor.syn_frame_count_);
    514   EXPECT_EQ(0, visitor.syn_reply_frame_count_);
    515   EXPECT_EQ(1, visitor.headers_frame_count_);
    516   EXPECT_EQ(24, visitor.data_bytes_);
    517   EXPECT_EQ(2, visitor.fin_frame_count_);
    518   EXPECT_EQ(0, visitor.fin_flag_count_);
    519   EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
    520 }
    521 
    522 // Test that the FIN flag on a data frame signifies EOF.
    523 TEST_F(SpdyFramerTest, FinOnDataFrame) {
    524   const unsigned char input[] = {
    525     0x80, 0x02, 0x00, 0x01,   // SYN Stream #1
    526     0x00, 0x00, 0x00, 0x14,
    527     0x00, 0x00, 0x00, 0x01,
    528     0x00, 0x00, 0x00, 0x00,
    529     0x00, 0x00, 0x00, 0x01,
    530     0x00, 0x02, 'h', 'h',
    531     0x00, 0x02, 'v', 'v',
    532 
    533     0x80, 0x02, 0x00, 0x02,   // SYN REPLY Stream #1
    534     0x00, 0x00, 0x00, 0x10,
    535     0x00, 0x00, 0x00, 0x01,
    536     0x00, 0x00, 0x00, 0x01,
    537     0x00, 0x02, 'a', 'a',
    538     0x00, 0x02, 'b', 'b',
    539 
    540     0x00, 0x00, 0x00, 0x01,   // DATA on Stream #1
    541     0x00, 0x00, 0x00, 0x0c,
    542       0xde, 0xad, 0xbe, 0xef,
    543       0xde, 0xad, 0xbe, 0xef,
    544       0xde, 0xad, 0xbe, 0xef,
    545 
    546     0x00, 0x00, 0x00, 0x01,   // DATA on Stream #1, with EOF
    547     0x01, 0x00, 0x00, 0x04,
    548       0xde, 0xad, 0xbe, 0xef,
    549   };
    550 
    551   TestSpdyVisitor visitor;
    552   visitor.SimulateInFramer(input, sizeof(input));
    553 
    554   EXPECT_EQ(0, visitor.error_count_);
    555   EXPECT_EQ(1, visitor.syn_frame_count_);
    556   EXPECT_EQ(1, visitor.syn_reply_frame_count_);
    557   EXPECT_EQ(0, visitor.headers_frame_count_);
    558   EXPECT_EQ(16, visitor.data_bytes_);
    559   EXPECT_EQ(0, visitor.fin_frame_count_);
    560   EXPECT_EQ(0, visitor.fin_flag_count_);
    561   EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
    562 }
    563 
    564 // Test that the FIN flag on a SYN reply frame signifies EOF.
    565 TEST_F(SpdyFramerTest, FinOnSynReplyFrame) {
    566   const unsigned char input[] = {
    567     0x80, 0x02, 0x00, 0x01,   // SYN Stream #1
    568     0x00, 0x00, 0x00, 0x14,
    569     0x00, 0x00, 0x00, 0x01,
    570     0x00, 0x00, 0x00, 0x00,
    571     0x00, 0x00, 0x00, 0x01,
    572     0x00, 0x02, 'h', 'h',
    573     0x00, 0x02, 'v', 'v',
    574 
    575     0x80, 0x02, 0x00, 0x02,   // SYN REPLY Stream #1
    576     0x01, 0x00, 0x00, 0x10,
    577     0x00, 0x00, 0x00, 0x01,
    578     0x00, 0x00, 0x00, 0x01,
    579     0x00, 0x02, 'a', 'a',
    580     0x00, 0x02, 'b', 'b',
    581   };
    582 
    583   TestSpdyVisitor visitor;
    584   visitor.SimulateInFramer(input, sizeof(input));
    585 
    586   EXPECT_EQ(0, visitor.error_count_);
    587   EXPECT_EQ(1, visitor.syn_frame_count_);
    588   EXPECT_EQ(1, visitor.syn_reply_frame_count_);
    589   EXPECT_EQ(0, visitor.headers_frame_count_);
    590   EXPECT_EQ(0, visitor.data_bytes_);
    591   EXPECT_EQ(0, visitor.fin_frame_count_);
    592   EXPECT_EQ(1, visitor.fin_flag_count_);
    593   EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
    594 }
    595 
    596 // Basic compression & decompression
    597 TEST_F(SpdyFramerTest, DataCompression) {
    598   SpdyFramer send_framer;
    599   SpdyFramer recv_framer;
    600 
    601   FramerSetEnableCompressionHelper(&send_framer, true);
    602   FramerSetEnableCompressionHelper(&recv_framer, true);
    603 
    604   // Mix up some SYNs and DATA frames since they use different compressors.
    605   const char kHeader1[] = "header1";
    606   const char kHeader2[] = "header2";
    607   const char kHeader3[] = "header3";
    608   const char kValue1[] = "value1";
    609   const char kValue2[] = "value2";
    610   const char kValue3[] = "value3";
    611 
    612   // SYN_STREAM #1
    613   SpdyHeaderBlock block;
    614   block[kHeader1] = kValue1;
    615   block[kHeader2] = kValue2;
    616   SpdyControlFlags flags(CONTROL_FLAG_NONE);
    617   scoped_ptr<spdy::SpdyFrame> syn_frame_1(
    618       send_framer.CreateSynStream(1, 0, 0, flags, true, &block));
    619   EXPECT_TRUE(syn_frame_1.get() != NULL);
    620 
    621   // DATA #1
    622   const char bytes[] = "this is a test test test test test!";
    623   scoped_ptr<SpdyFrame> data_frame_1(
    624       send_framer.CreateDataFrame(1, bytes, arraysize(bytes),
    625                                   DATA_FLAG_COMPRESSED));
    626   EXPECT_TRUE(data_frame_1.get() != NULL);
    627 
    628   // SYN_STREAM #2
    629   block[kHeader3] = kValue3;
    630   scoped_ptr<SpdyFrame> syn_frame_2(
    631       send_framer.CreateSynStream(3, 0, 0, flags, true, &block));
    632   EXPECT_TRUE(syn_frame_2.get() != NULL);
    633 
    634   // DATA #2
    635   scoped_ptr<SpdyFrame> data_frame_2(
    636       send_framer.CreateDataFrame(3, bytes, arraysize(bytes),
    637                                   DATA_FLAG_COMPRESSED));
    638   EXPECT_TRUE(data_frame_2.get() != NULL);
    639 
    640   // Now start decompressing
    641   scoped_ptr<SpdyFrame> decompressed;
    642   SpdyControlFrame* control_frame;
    643   SpdyDataFrame* data_frame;
    644   SpdyHeaderBlock decompressed_headers;
    645 
    646   decompressed.reset(recv_framer.DuplicateFrame(*syn_frame_1.get()));
    647   EXPECT_TRUE(decompressed.get() != NULL);
    648   EXPECT_TRUE(decompressed->is_control_frame());
    649   control_frame = reinterpret_cast<SpdyControlFrame*>(decompressed.get());
    650   EXPECT_EQ(SYN_STREAM, control_frame->type());
    651   EXPECT_TRUE(recv_framer.ParseHeaderBlock(
    652       control_frame, &decompressed_headers));
    653   EXPECT_EQ(2u, decompressed_headers.size());
    654   EXPECT_EQ(SYN_STREAM, control_frame->type());
    655   EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
    656   EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
    657 
    658   decompressed.reset(recv_framer.DecompressFrame(*data_frame_1.get()));
    659   EXPECT_TRUE(decompressed.get() != NULL);
    660   EXPECT_FALSE(decompressed->is_control_frame());
    661   data_frame = reinterpret_cast<SpdyDataFrame*>(decompressed.get());
    662   EXPECT_EQ(arraysize(bytes), data_frame->length());
    663   EXPECT_EQ(0, memcmp(data_frame->payload(), bytes, data_frame->length()));
    664 
    665   decompressed.reset(recv_framer.DuplicateFrame(*syn_frame_2.get()));
    666   EXPECT_TRUE(decompressed.get() != NULL);
    667   EXPECT_TRUE(decompressed->is_control_frame());
    668   control_frame = reinterpret_cast<SpdyControlFrame*>(decompressed.get());
    669   EXPECT_EQ(control_frame->type(), SYN_STREAM);
    670   decompressed_headers.clear();
    671   EXPECT_TRUE(recv_framer.ParseHeaderBlock(
    672       control_frame, &decompressed_headers));
    673   EXPECT_EQ(3u, decompressed_headers.size());
    674   EXPECT_EQ(SYN_STREAM, control_frame->type());
    675   EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
    676   EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
    677   EXPECT_EQ(kValue3, decompressed_headers[kHeader3]);
    678 
    679   decompressed.reset(recv_framer.DecompressFrame(*data_frame_2.get()));
    680   EXPECT_TRUE(decompressed.get() != NULL);
    681   EXPECT_FALSE(decompressed->is_control_frame());
    682   data_frame = reinterpret_cast<SpdyDataFrame*>(decompressed.get());
    683   EXPECT_EQ(arraysize(bytes), data_frame->length());
    684   EXPECT_EQ(0, memcmp(data_frame->payload(), bytes, data_frame->length()));
    685 
    686   // We didn't close these streams, so the compressors should be active.
    687   EXPECT_EQ(2, send_framer.num_stream_compressors());
    688   EXPECT_EQ(0, send_framer.num_stream_decompressors());
    689   EXPECT_EQ(0, recv_framer.num_stream_compressors());
    690   EXPECT_EQ(2, recv_framer.num_stream_decompressors());
    691 }
    692 
    693 // Verify we don't leak when we leave streams unclosed
    694 TEST_F(SpdyFramerTest, UnclosedStreamDataCompressors) {
    695   SpdyFramer send_framer;
    696 
    697   FramerSetEnableCompressionHelper(&send_framer, false);
    698 
    699   const char kHeader1[] = "header1";
    700   const char kHeader2[] = "header2";
    701   const char kValue1[] = "value1";
    702   const char kValue2[] = "value2";
    703 
    704   SpdyHeaderBlock block;
    705   block[kHeader1] = kValue1;
    706   block[kHeader2] = kValue2;
    707   SpdyControlFlags flags(CONTROL_FLAG_NONE);
    708   scoped_ptr<spdy::SpdyFrame> syn_frame(
    709       send_framer.CreateSynStream(1, 0, 0, flags, true, &block));
    710   EXPECT_TRUE(syn_frame.get() != NULL);
    711 
    712   const char bytes[] = "this is a test test test test test!";
    713   scoped_ptr<SpdyFrame> send_frame(
    714       send_framer.CreateDataFrame(1,
    715                                   bytes,
    716                                   arraysize(bytes),
    717                                   DATA_FLAG_FIN));
    718   EXPECT_TRUE(send_frame.get() != NULL);
    719 
    720   // Run the inputs through the framer.
    721   TestSpdyVisitor visitor;
    722   const unsigned char* data;
    723   data = reinterpret_cast<const unsigned char*>(syn_frame->data());
    724   visitor.SimulateInFramer(data, syn_frame->length() + SpdyFrame::size());
    725   data = reinterpret_cast<const unsigned char*>(send_frame->data());
    726   visitor.SimulateInFramer(data, send_frame->length() + SpdyFrame::size());
    727 
    728   EXPECT_EQ(0, visitor.error_count_);
    729   EXPECT_EQ(1, visitor.syn_frame_count_);
    730   EXPECT_EQ(0, visitor.syn_reply_frame_count_);
    731   EXPECT_EQ(0, visitor.headers_frame_count_);
    732   EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_));
    733   EXPECT_EQ(0, visitor.fin_frame_count_);
    734   EXPECT_EQ(0, visitor.fin_flag_count_);
    735   EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
    736 
    737   // We closed the streams, so all compressors should be down.
    738   EXPECT_EQ(0, visitor.framer_.num_stream_compressors());
    739   EXPECT_EQ(0, visitor.framer_.num_stream_decompressors());
    740   EXPECT_EQ(0, send_framer.num_stream_compressors());
    741   EXPECT_EQ(0, send_framer.num_stream_decompressors());
    742 }
    743 
    744 TEST_F(SpdyFramerTest, CreateDataFrame) {
    745   SpdyFramer framer;
    746 
    747   {
    748     const char kDescription[] = "'hello' data frame, no FIN";
    749     const unsigned char kFrameData[] = {
    750       0x00, 0x00, 0x00, 0x01,
    751       0x00, 0x00, 0x00, 0x05,
    752       'h', 'e', 'l', 'l',
    753       'o'
    754     };
    755     scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
    756         1, "hello", 5, DATA_FLAG_NONE));
    757     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
    758   }
    759 
    760   {
    761     const char kDescription[] = "Data frame with negative data byte, no FIN";
    762     const unsigned char kFrameData[] = {
    763       0x00, 0x00, 0x00, 0x01,
    764       0x00, 0x00, 0x00, 0x01,
    765       0xff
    766     };
    767     scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
    768         1, "\xff", 1, DATA_FLAG_NONE));
    769     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
    770   }
    771 
    772   {
    773     const char kDescription[] = "'hello' data frame, with FIN";
    774     const unsigned char kFrameData[] = {
    775       0x00, 0x00, 0x00, 0x01,
    776       0x01, 0x00, 0x00, 0x05,
    777       'h', 'e', 'l', 'l',
    778       'o'
    779     };
    780     scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
    781         1, "hello", 5, DATA_FLAG_FIN));
    782     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
    783   }
    784 
    785   {
    786     const char kDescription[] = "Empty data frame";
    787     const unsigned char kFrameData[] = {
    788       0x00, 0x00, 0x00, 0x01,
    789       0x00, 0x00, 0x00, 0x00,
    790     };
    791     scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
    792         1, "", 0, DATA_FLAG_NONE));
    793     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
    794   }
    795 
    796   {
    797     const char kDescription[] = "Data frame with max stream ID";
    798     const unsigned char kFrameData[] = {
    799       0x7f, 0xff, 0xff, 0xff,
    800       0x01, 0x00, 0x00, 0x05,
    801       'h', 'e', 'l', 'l',
    802       'o'
    803     };
    804     scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
    805         0x7fffffff, "hello", 5, DATA_FLAG_FIN));
    806     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
    807   }
    808 }
    809 
    810 TEST_F(SpdyFramerTest, CreateSynStreamUncompressed) {
    811   SpdyFramer framer;
    812   FramerSetEnableCompressionHelper(&framer, false);
    813 
    814   {
    815     const char kDescription[] = "SYN_STREAM frame, lowest pri, no FIN";
    816 
    817     SpdyHeaderBlock headers;
    818     headers["bar"] = "foo";
    819     headers["foo"] = "bar";
    820 
    821     const unsigned char kFrameData[] = {
    822       0x80, 0x02, 0x00, 0x01,
    823       0x00, 0x00, 0x00, 0x20,
    824       0x00, 0x00, 0x00, 0x01,
    825       0x00, 0x00, 0x00, 0x00,
    826       0xC0, 0x00, 0x00, 0x02,
    827       0x00, 0x03, 'b',  'a',
    828       'r',  0x00, 0x03, 'f',
    829       'o',  'o',  0x00, 0x03,
    830       'f',  'o',  'o',  0x00,
    831       0x03, 'b',  'a',  'r'
    832     };
    833     scoped_ptr<SpdyFrame> frame(framer.CreateSynStream(
    834         1, 0, SPDY_PRIORITY_LOWEST, CONTROL_FLAG_NONE,
    835         false, &headers));
    836     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
    837   }
    838 
    839   {
    840     const char kDescription[] =
    841         "SYN_STREAM frame with a 0-length header name, highest pri, FIN, "
    842         "max stream ID";
    843 
    844     SpdyHeaderBlock headers;
    845     headers[""] = "foo";
    846     headers["foo"] = "bar";
    847 
    848     const unsigned char kFrameData[] = {
    849       0x80, 0x02, 0x00, 0x01,
    850       0x01, 0x00, 0x00, 0x1D,
    851       0x7f, 0xff, 0xff, 0xff,
    852       0x7f, 0xff, 0xff, 0xff,
    853       0x00, 0x00, 0x00, 0x02,
    854       0x00, 0x00, 0x00, 0x03,
    855       'f',  'o',  'o',  0x00,
    856       0x03, 'f',  'o',  'o',
    857       0x00, 0x03, 'b',  'a',
    858       'r'
    859     };
    860     scoped_ptr<SpdyFrame> frame(framer.CreateSynStream(
    861         0x7fffffff, 0x7fffffff, SPDY_PRIORITY_HIGHEST, CONTROL_FLAG_FIN,
    862         false, &headers));
    863     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
    864   }
    865 
    866   {
    867     const char kDescription[] =
    868         "SYN_STREAM frame with a 0-length header val, highest pri, FIN, "
    869         "max stream ID";
    870 
    871     SpdyHeaderBlock headers;
    872     headers["bar"] = "foo";
    873     headers["foo"] = "";
    874 
    875     const unsigned char kFrameData[] = {
    876       0x80, 0x02, 0x00, 0x01,
    877       0x01, 0x00, 0x00, 0x1D,
    878       0x7f, 0xff, 0xff, 0xff,
    879       0x7f, 0xff, 0xff, 0xff,
    880       0x00, 0x00, 0x00, 0x02,
    881       0x00, 0x03, 'b',  'a',
    882       'r',  0x00, 0x03, 'f',
    883       'o',  'o',  0x00, 0x03,
    884       'f',  'o',  'o',  0x00,
    885       0x00
    886     };
    887     scoped_ptr<SpdyFrame> frame(framer.CreateSynStream(
    888         0x7fffffff, 0x7fffffff, SPDY_PRIORITY_HIGHEST, CONTROL_FLAG_FIN,
    889         false, &headers));
    890     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
    891   }
    892 }
    893 
    894 TEST_F(SpdyFramerTest, CreateSynStreamCompressed) {
    895   SpdyFramer framer;
    896   FramerSetEnableCompressionHelper(&framer, true);
    897 
    898   {
    899     const char kDescription[] =
    900         "SYN_STREAM frame, lowest pri, no FIN";
    901 
    902     SpdyHeaderBlock headers;
    903     headers["bar"] = "foo";
    904     headers["foo"] = "bar";
    905 
    906     const unsigned char kFrameData[] = {
    907       0x80, 0x02, 0x00, 0x01,
    908       0x00, 0x00, 0x00, 0x25,
    909       0x00, 0x00, 0x00, 0x01,
    910       0x00, 0x00, 0x00, 0x00,
    911       0xC0, 0x00, 0x38, 0xea,
    912       0xdf, 0xa2, 0x51, 0xb2,
    913       0x62, 0x60, 0x62, 0x60,
    914       0x4e, 0x4a, 0x2c, 0x62,
    915       0x60, 0x4e, 0xcb, 0xcf,
    916       0x87, 0x12, 0x40, 0x2e,
    917       0x00, 0x00, 0x00, 0xff,
    918       0xff
    919     };
    920     scoped_ptr<SpdyFrame> frame(framer.CreateSynStream(
    921         1, 0, SPDY_PRIORITY_LOWEST, CONTROL_FLAG_NONE,
    922         true, &headers));
    923     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
    924   }
    925 }
    926 
    927 TEST_F(SpdyFramerTest, CreateSynReplyUncompressed) {
    928   SpdyFramer framer;
    929   FramerSetEnableCompressionHelper(&framer, false);
    930 
    931   {
    932     const char kDescription[] = "SYN_REPLY frame, no FIN";
    933 
    934     SpdyHeaderBlock headers;
    935     headers["bar"] = "foo";
    936     headers["foo"] = "bar";
    937 
    938     const unsigned char kFrameData[] = {
    939       0x80, 0x02, 0x00, 0x02,
    940       0x00, 0x00, 0x00, 0x1C,
    941       0x00, 0x00, 0x00, 0x01,
    942       0x00, 0x00, 0x00, 0x02,
    943       0x00, 0x03, 'b',  'a',
    944       'r',  0x00, 0x03, 'f',
    945       'o',  'o',  0x00, 0x03,
    946       'f',  'o',  'o',  0x00,
    947       0x03, 'b',  'a',  'r'
    948     };
    949     scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
    950         1, CONTROL_FLAG_NONE, false, &headers));
    951     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
    952   }
    953 
    954   {
    955     const char kDescription[] =
    956         "SYN_REPLY frame with a 0-length header name, FIN, max stream ID";
    957 
    958     SpdyHeaderBlock headers;
    959     headers[""] = "foo";
    960     headers["foo"] = "bar";
    961 
    962     const unsigned char kFrameData[] = {
    963       0x80, 0x02, 0x00, 0x02,
    964       0x01, 0x00, 0x00, 0x19,
    965       0x7f, 0xff, 0xff, 0xff,
    966       0x00, 0x00, 0x00, 0x02,
    967       0x00, 0x00, 0x00, 0x03,
    968       'f',  'o',  'o',  0x00,
    969       0x03, 'f',  'o',  'o',
    970       0x00, 0x03, 'b',  'a',
    971       'r'
    972     };
    973     scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
    974         0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
    975     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
    976   }
    977 
    978   {
    979     const char kDescription[] =
    980         "SYN_REPLY frame with a 0-length header val, FIN, max stream ID";
    981 
    982     SpdyHeaderBlock headers;
    983     headers["bar"] = "foo";
    984     headers["foo"] = "";
    985 
    986     const unsigned char kFrameData[] = {
    987       0x80, 0x02, 0x00, 0x02,
    988       0x01, 0x00, 0x00, 0x19,
    989       0x7f, 0xff, 0xff, 0xff,
    990       0x00, 0x00, 0x00, 0x02,
    991       0x00, 0x03, 'b',  'a',
    992       'r',  0x00, 0x03, 'f',
    993       'o',  'o',  0x00, 0x03,
    994       'f',  'o',  'o',  0x00,
    995       0x00
    996     };
    997     scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
    998         0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
    999     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1000   }
   1001 }
   1002 
   1003 TEST_F(SpdyFramerTest, CreateSynReplyCompressed) {
   1004   SpdyFramer framer;
   1005   FramerSetEnableCompressionHelper(&framer, true);
   1006 
   1007   {
   1008     const char kDescription[] = "SYN_REPLY frame, no FIN";
   1009 
   1010     SpdyHeaderBlock headers;
   1011     headers["bar"] = "foo";
   1012     headers["foo"] = "bar";
   1013 
   1014     const unsigned char kFrameData[] = {
   1015       0x80, 0x02, 0x00, 0x02,
   1016       0x00, 0x00, 0x00, 0x21,
   1017       0x00, 0x00, 0x00, 0x01,
   1018       0x00, 0x00, 0x38, 0xea,
   1019       0xdf, 0xa2, 0x51, 0xb2,
   1020       0x62, 0x60, 0x62, 0x60,
   1021       0x4e, 0x4a, 0x2c, 0x62,
   1022       0x60, 0x4e, 0xcb, 0xcf,
   1023       0x87, 0x12, 0x40, 0x2e,
   1024       0x00, 0x00, 0x00, 0xff,
   1025       0xff
   1026     };
   1027     scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
   1028         1, CONTROL_FLAG_NONE, true, &headers));
   1029     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1030   }
   1031 }
   1032 
   1033 TEST_F(SpdyFramerTest, CreateRstStream) {
   1034   SpdyFramer framer;
   1035 
   1036   {
   1037     const char kDescription[] = "RST_STREAM frame";
   1038     const unsigned char kFrameData[] = {
   1039       0x80, 0x02, 0x00, 0x03,
   1040       0x00, 0x00, 0x00, 0x08,
   1041       0x00, 0x00, 0x00, 0x01,
   1042       0x00, 0x00, 0x00, 0x01,
   1043     };
   1044     scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(1, PROTOCOL_ERROR));
   1045     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1046   }
   1047 
   1048   {
   1049     const char kDescription[] = "RST_STREAM frame with max stream ID";
   1050     const unsigned char kFrameData[] = {
   1051       0x80, 0x02, 0x00, 0x03,
   1052       0x00, 0x00, 0x00, 0x08,
   1053       0x7f, 0xff, 0xff, 0xff,
   1054       0x00, 0x00, 0x00, 0x01,
   1055     };
   1056     scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF,
   1057                                                        PROTOCOL_ERROR));
   1058     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1059   }
   1060 
   1061   {
   1062     const char kDescription[] = "RST_STREAM frame with max status code";
   1063     const unsigned char kFrameData[] = {
   1064       0x80, 0x02, 0x00, 0x03,
   1065       0x00, 0x00, 0x00, 0x08,
   1066       0x7f, 0xff, 0xff, 0xff,
   1067       0x00, 0x00, 0x00, 0x06,
   1068     };
   1069     scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF,
   1070                                                        INTERNAL_ERROR));
   1071     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1072   }
   1073 }
   1074 
   1075 TEST_F(SpdyFramerTest, CreateSettings) {
   1076   SpdyFramer framer;
   1077 
   1078   {
   1079     const char kDescription[] = "Basic SETTINGS frame";
   1080 
   1081     SpdySettings settings;
   1082     settings.push_back(SpdySetting(0x00000000, 0x00000000));
   1083     settings.push_back(SpdySetting(0xffffffff, 0x00000001));
   1084     settings.push_back(SpdySetting(0xff000001, 0x00000002));
   1085 
   1086     // Duplicates allowed
   1087     settings.push_back(SpdySetting(0x01000002, 0x00000003));
   1088     settings.push_back(SpdySetting(0x01000002, 0x00000003));
   1089 
   1090     settings.push_back(SpdySetting(0x01000003, 0x000000ff));
   1091     settings.push_back(SpdySetting(0x01000004, 0xff000001));
   1092     settings.push_back(SpdySetting(0x01000004, 0xffffffff));
   1093 
   1094     const unsigned char kFrameData[] = {
   1095       0x80, 0x02, 0x00, 0x04,
   1096       0x00, 0x00, 0x00, 0x44,
   1097       0x00, 0x00, 0x00, 0x08,
   1098       0x00, 0x00, 0x00, 0x00,
   1099       0x00, 0x00, 0x00, 0x00,
   1100       0xff, 0xff, 0xff, 0xff,
   1101       0x00, 0x00, 0x00, 0x01,
   1102       0xff, 0x00, 0x00, 0x01,
   1103       0x00, 0x00, 0x00, 0x02,
   1104       0x01, 0x00, 0x00, 0x02,
   1105       0x00, 0x00, 0x00, 0x03,
   1106       0x01, 0x00, 0x00, 0x02,
   1107       0x00, 0x00, 0x00, 0x03,
   1108       0x01, 0x00, 0x00, 0x03,
   1109       0x00, 0x00, 0x00, 0xff,
   1110       0x01, 0x00, 0x00, 0x04,
   1111       0xff, 0x00, 0x00, 0x01,
   1112       0x01, 0x00, 0x00, 0x04,
   1113       0xff, 0xff, 0xff, 0xff,
   1114     };
   1115     scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
   1116     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1117   }
   1118 
   1119   {
   1120     const char kDescription[] = "Empty SETTINGS frame";
   1121 
   1122     SpdySettings settings;
   1123 
   1124     const unsigned char kFrameData[] = {
   1125       0x80, 0x02, 0x00, 0x04,
   1126       0x00, 0x00, 0x00, 0x04,
   1127       0x00, 0x00, 0x00, 0x00,
   1128     };
   1129     scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
   1130     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1131   }
   1132 }
   1133 
   1134 TEST_F(SpdyFramerTest, CreateNopFrame) {
   1135   SpdyFramer framer;
   1136 
   1137   {
   1138     const char kDescription[] = "NOOP frame";
   1139     const unsigned char kFrameData[] = {
   1140       0x80, 0x02, 0x00, 0x05,
   1141       0x00, 0x00, 0x00, 0x00,
   1142     };
   1143     scoped_ptr<SpdyFrame> frame(framer.CreateNopFrame());
   1144     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1145   }
   1146 }
   1147 
   1148 TEST_F(SpdyFramerTest, CreateGoAway) {
   1149   SpdyFramer framer;
   1150 
   1151   {
   1152     const char kDescription[] = "GOAWAY frame";
   1153     const unsigned char kFrameData[] = {
   1154       0x80, 0x02, 0x00, 0x07,
   1155       0x00, 0x00, 0x00, 0x04,
   1156       0x00, 0x00, 0x00, 0x00,
   1157     };
   1158     scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0));
   1159     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1160   }
   1161 
   1162   {
   1163     const char kDescription[] = "GOAWAY frame with max stream ID";
   1164     const unsigned char kFrameData[] = {
   1165       0x80, 0x02, 0x00, 0x07,
   1166       0x00, 0x00, 0x00, 0x04,
   1167       0x7f, 0xff, 0xff, 0xff,
   1168     };
   1169     scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF));
   1170     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1171   }
   1172 }
   1173 
   1174 TEST_F(SpdyFramerTest, CreateHeadersUncompressed) {
   1175   SpdyFramer framer;
   1176   FramerSetEnableCompressionHelper(&framer, false);
   1177 
   1178   {
   1179     const char kDescription[] = "HEADERS frame, no FIN";
   1180 
   1181     SpdyHeaderBlock headers;
   1182     headers["bar"] = "foo";
   1183     headers["foo"] = "bar";
   1184 
   1185     const unsigned char kFrameData[] = {
   1186       0x80, 0x02, 0x00, 0x08,
   1187       0x00, 0x00, 0x00, 0x1C,
   1188       0x00, 0x00, 0x00, 0x01,
   1189       0x00, 0x00, 0x00, 0x02,
   1190       0x00, 0x03, 'b',  'a',
   1191       'r',  0x00, 0x03, 'f',
   1192       'o',  'o',  0x00, 0x03,
   1193       'f',  'o',  'o',  0x00,
   1194       0x03, 'b',  'a',  'r'
   1195     };
   1196     scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
   1197         1, CONTROL_FLAG_NONE, false, &headers));
   1198     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1199   }
   1200 
   1201   {
   1202     const char kDescription[] =
   1203         "HEADERS frame with a 0-length header name, FIN, max stream ID";
   1204 
   1205     SpdyHeaderBlock headers;
   1206     headers[""] = "foo";
   1207     headers["foo"] = "bar";
   1208 
   1209     const unsigned char kFrameData[] = {
   1210       0x80, 0x02, 0x00, 0x08,
   1211       0x01, 0x00, 0x00, 0x19,
   1212       0x7f, 0xff, 0xff, 0xff,
   1213       0x00, 0x00, 0x00, 0x02,
   1214       0x00, 0x00, 0x00, 0x03,
   1215       'f',  'o',  'o',  0x00,
   1216       0x03, 'f',  'o',  'o',
   1217       0x00, 0x03, 'b',  'a',
   1218       'r'
   1219     };
   1220     scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
   1221         0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
   1222     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1223   }
   1224 
   1225   {
   1226     const char kDescription[] =
   1227         "HEADERS frame with a 0-length header val, FIN, max stream ID";
   1228 
   1229     SpdyHeaderBlock headers;
   1230     headers["bar"] = "foo";
   1231     headers["foo"] = "";
   1232 
   1233     const unsigned char kFrameData[] = {
   1234       0x80, 0x02, 0x00, 0x08,
   1235       0x01, 0x00, 0x00, 0x19,
   1236       0x7f, 0xff, 0xff, 0xff,
   1237       0x00, 0x00, 0x00, 0x02,
   1238       0x00, 0x03, 'b',  'a',
   1239       'r',  0x00, 0x03, 'f',
   1240       'o',  'o',  0x00, 0x03,
   1241       'f',  'o',  'o',  0x00,
   1242       0x00
   1243     };
   1244     scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
   1245         0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
   1246     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1247   }
   1248 }
   1249 
   1250 TEST_F(SpdyFramerTest, CreateHeadersCompressed) {
   1251   SpdyFramer framer;
   1252   FramerSetEnableCompressionHelper(&framer, true);
   1253 
   1254   {
   1255     const char kDescription[] = "HEADERS frame, no FIN";
   1256 
   1257     SpdyHeaderBlock headers;
   1258     headers["bar"] = "foo";
   1259     headers["foo"] = "bar";
   1260 
   1261     const unsigned char kFrameData[] = {
   1262       0x80, 0x02, 0x00, 0x08,
   1263       0x00, 0x00, 0x00, 0x21,
   1264       0x00, 0x00, 0x00, 0x01,
   1265       0x00, 0x00, 0x38, 0xea,
   1266       0xdf, 0xa2, 0x51, 0xb2,
   1267       0x62, 0x60, 0x62, 0x60,
   1268       0x4e, 0x4a, 0x2c, 0x62,
   1269       0x60, 0x4e, 0xcb, 0xcf,
   1270       0x87, 0x12, 0x40, 0x2e,
   1271       0x00, 0x00, 0x00, 0xff,
   1272       0xff
   1273     };
   1274     scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
   1275         1, CONTROL_FLAG_NONE, true, &headers));
   1276     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1277   }
   1278 }
   1279 
   1280 TEST_F(SpdyFramerTest, CreateWindowUpdate) {
   1281   SpdyFramer framer;
   1282 
   1283   {
   1284     const char kDescription[] = "WINDOW_UPDATE frame";
   1285     const unsigned char kFrameData[] = {
   1286       0x80, 0x02, 0x00, 0x09,
   1287       0x00, 0x00, 0x00, 0x08,
   1288       0x00, 0x00, 0x00, 0x01,
   1289       0x00, 0x00, 0x00, 0x01,
   1290     };
   1291     scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 1));
   1292     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1293   }
   1294 
   1295   {
   1296     const char kDescription[] = "WINDOW_UPDATE frame with max stream ID";
   1297     const unsigned char kFrameData[] = {
   1298       0x80, 0x02, 0x00, 0x09,
   1299       0x00, 0x00, 0x00, 0x08,
   1300       0x7f, 0xff, 0xff, 0xff,
   1301       0x00, 0x00, 0x00, 0x01,
   1302     };
   1303     scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(0x7FFFFFFF, 1));
   1304     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1305   }
   1306 
   1307   {
   1308     const char kDescription[] = "WINDOW_UPDATE frame with max window delta";
   1309     const unsigned char kFrameData[] = {
   1310       0x80, 0x02, 0x00, 0x09,
   1311       0x00, 0x00, 0x00, 0x08,
   1312       0x00, 0x00, 0x00, 0x01,
   1313       0x7f, 0xff, 0xff, 0xff,
   1314     };
   1315     scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x7FFFFFFF));
   1316     CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
   1317   }
   1318 }
   1319 
   1320 // This test case reproduces conditions that caused ExpandControlFrameBuffer to
   1321 // fail to expand the buffer control frame buffer when it should have, allowing
   1322 // the framer to overrun the buffer, and smash other heap contents. This test
   1323 // relies on the debug version of the heap manager, which checks for buffer
   1324 // overrun errors during delete processing. Regression test for b/2974814.
   1325 TEST_F(SpdyFramerTest, ExpandBuffer_HeapSmash) {
   1326   // Sweep through the area of problematic values, to make sure we always cover
   1327   // the danger zone, even if it moves around at bit due to SPDY changes.
   1328   for (uint16 val2_len = SpdyFramer::kControlFrameBufferInitialSize - 50;
   1329        val2_len < SpdyFramer::kControlFrameBufferInitialSize;
   1330        val2_len++) {
   1331     std::string val2 = std::string(val2_len, 'a');
   1332     SpdyHeaderBlock headers;
   1333     headers["bar"] = "foo";
   1334     headers["foo"] = "baz";
   1335     headers["grue"] = val2.c_str();
   1336     SpdyFramer framer;
   1337     scoped_ptr<SpdySynStreamControlFrame> template_frame(
   1338         framer.CreateSynStream(1,                      // stream_id
   1339                                0,                      // associated_stream_id
   1340                                1,                      // priority
   1341                                CONTROL_FLAG_NONE,
   1342                                false,                  // compress
   1343                                &headers));
   1344     EXPECT_TRUE(template_frame.get() != NULL);
   1345     TestSpdyVisitor visitor;
   1346     visitor.SimulateInFramer(
   1347         reinterpret_cast<unsigned char*>(template_frame.get()->data()),
   1348          template_frame.get()->length() + SpdyControlFrame::size());
   1349     EXPECT_EQ(1, visitor.syn_frame_count_);
   1350   }
   1351 }
   1352 
   1353 std::string RandomString(int length) {
   1354   std::string rv;
   1355   for (int index = 0; index < length; index++)
   1356     rv += static_cast<char>('a' + (rand() % 26));
   1357   return rv;
   1358 }
   1359 
   1360 // Stress that we can handle a really large header block compression and
   1361 // decompression.
   1362 TEST_F(SpdyFramerTest, HugeHeaderBlock) {
   1363   // Loop targetting various sizes which will potentially jam up the
   1364   // frame compressor/decompressor.
   1365   SpdyFramer compress_framer;
   1366   SpdyFramer decompress_framer;
   1367   for (size_t target_size = 1024;
   1368        target_size < SpdyFramer::kControlFrameBufferInitialSize;
   1369        target_size += 1024) {
   1370     SpdyHeaderBlock headers;
   1371     for (size_t index = 0; index < target_size; ++index) {
   1372       std::string name = RandomString(4);
   1373       std::string value = RandomString(8);
   1374       headers[name] = value;
   1375     }
   1376 
   1377     // Encode the header block into a SynStream frame.
   1378     scoped_ptr<SpdySynStreamControlFrame> frame(
   1379         compress_framer.CreateSynStream(1,
   1380                                         0,
   1381                                         1,
   1382                                         CONTROL_FLAG_NONE,
   1383                                         true,
   1384                                         &headers));
   1385     // The point of this test is to exercise the limits.  So, it is ok if the
   1386     // frame was too large to encode, or if the decompress fails.  We just want
   1387     // to make sure we don't crash.
   1388     if (frame.get() != NULL) {
   1389       // Now that same header block should decompress just fine.
   1390       SpdyHeaderBlock new_headers;
   1391       decompress_framer.ParseHeaderBlock(frame.get(), &new_headers);
   1392     }
   1393   }
   1394 }
   1395 
   1396 }  // namespace
   1397