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