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