• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
HexDumpWithMarks(const unsigned char * data,int length,const bool * marks,int mark_length)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 
CompareCharArraysWithHexError(const std::string & description,const unsigned char * actual,const int actual_len,const unsigned char * expected,const int expected_len)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 
FramerSetEnableCompressionHelper(SpdyFramer * framer,bool compress)79 void FramerSetEnableCompressionHelper(SpdyFramer* framer, bool compress) {
80   framer->set_enable_compression(compress);
81 }
82 
83 class TestSpdyVisitor : public SpdyFramerVisitorInterface  {
84  public:
TestSpdyVisitor()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 
OnError(SpdyFramer * f)96   void OnError(SpdyFramer* f) {
97     error_count_++;
98   }
99 
OnStreamFrameData(SpdyStreamId stream_id,const char * data,size_t len)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 
OnControl(const SpdyControlFrame * frame)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 
OnControlFrameHeaderData(SpdyStreamId stream_id,const char * header_data,size_t len)145   bool OnControlFrameHeaderData(SpdyStreamId stream_id,
146                                 const char* header_data,
147                                 size_t len) {
148     DCHECK(false);
149     return false;
150   }
151 
OnDataFrameHeader(const SpdyDataFrame * frame)152   void OnDataFrameHeader(const SpdyDataFrame* frame) {
153     DCHECK(false);
154   }
155 
156   // Convenience function which runs a framer simulation with particular input.
SimulateInFramer(const unsigned char * input,size_t size)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:
TearDown()215   virtual void TearDown() {}
216 
217  protected:
CompareFrame(const std::string & description,const SpdyFrame & actual_frame,const unsigned char * expected,const int expected_len)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.
TEST_F(SpdyFramerTest,HeaderBlock)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 
TEST_F(SpdyFramerTest,OutOfOrderHeaders)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 
TEST_F(SpdyFramerTest,WrongNumberOfHeaders)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 
TEST_F(SpdyFramerTest,DuplicateHeader)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 
TEST_F(SpdyFramerTest,MultiValueHeader)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 
TEST_F(SpdyFramerTest,ZeroLengthHeader)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 
TEST_F(SpdyFramerTest,BasicCompression)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 
TEST_F(SpdyFramerTest,DecompressUncompressedFrame)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 
TEST_F(SpdyFramerTest,Basic)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.
TEST_F(SpdyFramerTest,FinOnDataFrame)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.
TEST_F(SpdyFramerTest,FinOnSynReplyFrame)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
TEST_F(SpdyFramerTest,DataCompression)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
TEST_F(SpdyFramerTest,UnclosedStreamDataCompressors)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 
TEST_F(SpdyFramerTest,CreateDataFrame)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 
TEST_F(SpdyFramerTest,CreateSynStreamUncompressed)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 
TEST_F(SpdyFramerTest,CreateSynStreamCompressed)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 
TEST_F(SpdyFramerTest,CreateSynReplyUncompressed)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 
TEST_F(SpdyFramerTest,CreateSynReplyCompressed)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 
TEST_F(SpdyFramerTest,CreateRstStream)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 
TEST_F(SpdyFramerTest,CreateSettings)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 
TEST_F(SpdyFramerTest,CreateNopFrame)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 
TEST_F(SpdyFramerTest,CreateGoAway)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 
TEST_F(SpdyFramerTest,CreateHeadersUncompressed)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 
TEST_F(SpdyFramerTest,CreateHeadersCompressed)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 
TEST_F(SpdyFramerTest,CreateWindowUpdate)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.
TEST_F(SpdyFramerTest,ExpandBuffer_HeapSmash)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 
RandomString(int length)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.
TEST_F(SpdyFramerTest,HugeHeaderBlock)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