Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(281)

Side by Side Diff: net/spdy/spdy_framer_spdy3_test.cc

Issue 9689078: SPDY - unforked spdy_framer and spdy_protocol tests. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/spdy/spdy_framer_spdy2_test.cc ('k') | net/spdy/spdy_framer_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 {
15
16 // Default SPDY version for unit tests.
17 const int SPDY_VERSION_FOR_TESTS = 3;
18
19 // The current default spdy version as a byte to be included in const
20 // byte arrays below. Name choice is unfortunate, but better to fit to four
21 // bytes than not.
22 unsigned char kVer = SPDY_VERSION_FOR_TESTS;
23
24 spdy::SpdySetting SpdySettingFromWireFormat(uint32 key, uint32 value) {
25 return spdy::SpdySetting(
26 spdy::SettingsFlagsAndId::FromWireFormat(SPDY_VERSION_FOR_TESTS, key),
27 value);
28 }
29
30 } // namespace
31
32 namespace spdy {
33
34 namespace test_spdy3 {
35
36 static const size_t kMaxDecompressedSize = 1024;
37
38 class SpdyFramerTestUtil {
39 public:
40 // Decompress a single frame using the decompression context held by
41 // the SpdyFramer. The implemention will CHECK fail if the input is anything
42 // other than a single, well-formed compressed frame.
43 //
44 // Returns a new decompressed SpdyFrame.
45 template<class SpdyFrameType> static SpdyFrame* DecompressFrame(
46 SpdyFramer* framer, const SpdyFrameType& frame) {
47 DecompressionVisitor visitor;
48 framer->set_visitor(&visitor);
49 size_t input_size = frame.length() + SpdyFrame::kHeaderSize;
50 CHECK_EQ(input_size, framer->ProcessInput(frame.data(), input_size));
51 CHECK_EQ(SpdyFramer::SPDY_RESET, framer->state());
52 framer->set_visitor(NULL);
53
54 char* buffer = visitor.ReleaseBuffer();
55 CHECK(buffer);
56 SpdyFrame* decompressed_frame = new SpdyFrame(buffer, true);
57 decompressed_frame->set_length(visitor.size() - SpdyFrame::kHeaderSize);
58 return decompressed_frame;
59 }
60
61 class DecompressionVisitor : public SpdyFramerVisitorInterface {
62 public:
63 DecompressionVisitor()
64 : buffer_(NULL), size_(0), finished_(false), allow_data_frames_(false) {
65 }
66
67 virtual void OnControl(const SpdyControlFrame* frame) {
68 CHECK(frame->has_header_block());
69 CHECK(!buffer_.get());
70 CHECK_EQ(size_, 0u);
71 CHECK(!finished_);
72
73 int32 control_frame_header_size = 0;
74 switch (frame->type()) {
75 case SYN_STREAM:
76 control_frame_header_size = SpdySynStreamControlFrame::size();
77 break;
78 case SYN_REPLY:
79 control_frame_header_size = SpdySynReplyControlFrame::size();
80 break;
81 case HEADERS:
82 control_frame_header_size = SpdyHeadersControlFrame::size();
83 break;
84 default:
85 LOG(FATAL);
86 return;
87 }
88
89 // Allocate space for the frame, and the copy header over.
90 buffer_.reset(new char[kMaxDecompressedSize]);
91 memcpy(buffer_.get(), frame->data(), control_frame_header_size);
92 size_ += control_frame_header_size;
93 }
94
95 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
96 const char* header_data,
97 size_t len) {
98 CHECK(buffer_.get() != NULL);
99 CHECK_GE(kMaxDecompressedSize, size_ + len);
100 CHECK(!finished_);
101 if (len != 0) {
102 memcpy(buffer_.get() + size_, header_data, len);
103 size_ += len;
104 } else {
105 // Done.
106 finished_ = true;
107 }
108 return true;
109 }
110
111 virtual bool OnCredentialFrameData(const char* header_data,
112 size_t len) {
113 LOG(FATAL) << "Unexpected CREDENTIAL Frame";
114 return false;
115 }
116
117 virtual void OnError(SpdyFramer* framer) { LOG(FATAL); }
118 virtual void OnDataFrameHeader(const SpdyDataFrame* frame) {
119 // For most tests, this class does not expect to see OnDataFrameHeader
120 // calls. Individual tests can override this if they need to.
121 if (!allow_data_frames_) {
122 LOG(FATAL) << "Unexpected data frame header";
123 }
124 }
125 virtual void OnStreamFrameData(SpdyStreamId stream_id,
126 const char* data,
127 size_t len) {
128 LOG(FATAL);
129 }
130 virtual void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) {
131 LOG(FATAL);
132 }
133
134 char* ReleaseBuffer() {
135 CHECK(finished_);
136 return buffer_.release();
137 }
138
139 size_t size() const {
140 CHECK(finished_);
141 return size_;
142 }
143 void set_allow_data_frames(bool allow) { allow_data_frames_ = allow; }
144
145 private:
146 scoped_array<char> buffer_;
147 size_t size_;
148 bool finished_;
149 bool allow_data_frames_;
150
151 DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor);
152 };
153
154 DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil);
155 };
156
157 std::string HexDumpWithMarks(const unsigned char* data, int length,
158 const bool* marks, int mark_length) {
159 static const char kHexChars[] = "0123456789abcdef";
160 static const int kColumns = 4;
161
162 const int kSizeLimit = 1024;
163 if (length > kSizeLimit || mark_length > kSizeLimit) {
164 LOG(ERROR) << "Only dumping first " << kSizeLimit << " bytes.";
165 length = std::min(length, kSizeLimit);
166 mark_length = std::min(mark_length, kSizeLimit);
167 }
168
169 std::string hex;
170 for (const unsigned char* row = data; length > 0;
171 row += kColumns, length -= kColumns) {
172 for (const unsigned char *p = row; p < row + 4; ++p) {
173 if (p < row + length) {
174 const bool mark =
175 (marks && (p - data) < mark_length && marks[p - data]);
176 hex += mark ? '*' : ' ';
177 hex += kHexChars[(*p & 0xf0) >> 4];
178 hex += kHexChars[*p & 0x0f];
179 hex += mark ? '*' : ' ';
180 } else {
181 hex += " ";
182 }
183 }
184 hex = hex + " ";
185
186 for (const unsigned char *p = row; p < row + 4 && p < row + length; ++p)
187 hex += (*p >= 0x20 && *p <= 0x7f) ? (*p) : '.';
188
189 hex = hex + '\n';
190 }
191 return hex;
192 }
193
194 void CompareCharArraysWithHexError(
195 const std::string& description,
196 const unsigned char* actual,
197 const int actual_len,
198 const unsigned char* expected,
199 const int expected_len) {
200 const int min_len = std::min(actual_len, expected_len);
201 const int max_len = std::max(actual_len, expected_len);
202 scoped_array<bool> marks(new bool[max_len]);
203 bool identical = (actual_len == expected_len);
204 for (int i = 0; i < min_len; ++i) {
205 if (actual[i] != expected[i]) {
206 marks[i] = true;
207 identical = false;
208 } else {
209 marks[i] = false;
210 }
211 }
212 for (int i = min_len; i < max_len; ++i) {
213 marks[i] = true;
214 }
215 if (identical) return;
216 ADD_FAILURE()
217 << "Description:\n"
218 << description
219 << "\n\nExpected:\n"
220 << HexDumpWithMarks(expected, expected_len, marks.get(), max_len)
221 << "\nActual:\n"
222 << HexDumpWithMarks(actual, actual_len, marks.get(), max_len);
223 }
224
225 class TestSpdyVisitor : public SpdyFramerVisitorInterface {
226 public:
227 static const size_t kDefaultHeaderBufferSize = 64 * 1024;
228 static const size_t kDefaultCredentialBufferSize = 16 * 1024;
229
230 TestSpdyVisitor()
231 : framer_(kVer),
232 use_compression_(false),
233 error_count_(0),
234 syn_frame_count_(0),
235 syn_reply_frame_count_(0),
236 headers_frame_count_(0),
237 goaway_count_(0),
238 credential_count_(0),
239 settings_frame_count_(0),
240 setting_count_(0),
241 data_bytes_(0),
242 fin_frame_count_(0),
243 fin_flag_count_(0),
244 zero_length_data_frame_count_(0),
245 header_blocks_count_(0),
246 control_frame_header_data_count_(0),
247 zero_length_control_frame_header_data_count_(0),
248 data_frame_count_(0),
249 header_buffer_(new char[kDefaultHeaderBufferSize]),
250 header_buffer_length_(0),
251 header_buffer_size_(kDefaultHeaderBufferSize),
252 header_stream_id_(-1),
253 header_control_type_(NUM_CONTROL_FRAME_TYPES),
254 header_buffer_valid_(false),
255 credential_buffer_(new char[kDefaultCredentialBufferSize]),
256 credential_buffer_length_(0),
257 credential_buffer_size_(kDefaultCredentialBufferSize) {
258 }
259
260 void OnError(SpdyFramer* f) {
261 LOG(INFO) << "SpdyFramer Error: "
262 << SpdyFramer::ErrorCodeToString(f->error_code());
263 error_count_++;
264 }
265
266 void OnDataFrameHeader(const SpdyDataFrame* frame) {
267 data_frame_count_++;
268 header_stream_id_ = frame->stream_id();
269 }
270
271 void OnStreamFrameData(SpdyStreamId stream_id,
272 const char* data,
273 size_t len) {
274 EXPECT_EQ(header_stream_id_, stream_id);
275 if (len == 0)
276 ++zero_length_data_frame_count_;
277
278 data_bytes_ += len;
279 std::cerr << "OnStreamFrameData(" << stream_id << ", \"";
280 if (len > 0) {
281 for (size_t i = 0 ; i < len; ++i) {
282 std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec;
283 }
284 }
285 std::cerr << "\", " << len << ")\n";
286 }
287
288 void OnControl(const SpdyControlFrame* frame) {
289 switch (frame->type()) {
290 case SYN_STREAM:
291 syn_frame_count_++;
292 InitHeaderStreaming(frame);
293 break;
294 case SYN_REPLY:
295 syn_reply_frame_count_++;
296 InitHeaderStreaming(frame);
297 break;
298 case RST_STREAM:
299 fin_frame_count_++;
300 break;
301 case HEADERS:
302 headers_frame_count_++;
303 InitHeaderStreaming(frame);
304 break;
305 case GOAWAY:
306 goaway_count_++;
307 break;
308 case CREDENTIAL:
309 credential_count_++;
310 break;
311 case SETTINGS:
312 settings_frame_count_++;
313 break;
314 default:
315 DLOG(FATAL); // Error!
316 }
317 if (frame->flags() & CONTROL_FLAG_FIN)
318 ++fin_flag_count_;
319 }
320
321 virtual void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) {
322 setting_count_++;
323 }
324
325 bool OnControlFrameHeaderData(SpdyStreamId stream_id,
326 const char* header_data,
327 size_t len) {
328 ++control_frame_header_data_count_;
329 CHECK_EQ(header_stream_id_, stream_id);
330 if (len == 0) {
331 ++zero_length_control_frame_header_data_count_;
332 // Indicates end-of-header-block.
333 CHECK(header_buffer_valid_);
334 bool parsed_headers = framer_.ParseHeaderBlockInBuffer(
335 header_buffer_.get(), header_buffer_length_, &headers_);
336 DCHECK(parsed_headers);
337 return true;
338 }
339 const size_t available = header_buffer_size_ - header_buffer_length_;
340 if (len > available) {
341 header_buffer_valid_ = false;
342 return false;
343 }
344 memcpy(header_buffer_.get() + header_buffer_length_, header_data, len);
345 header_buffer_length_ += len;
346 return true;
347 }
348
349 bool OnCredentialFrameData(const char* credential_data,
350 size_t len) {
351 if (len == 0) {
352 if (!framer_.ParseCredentialData(credential_buffer_.get(),
353 credential_buffer_length_,
354 &credential_)) {
355 ++error_count_;
356 }
357 return true;
358 }
359 const size_t available =
360 credential_buffer_size_ - credential_buffer_length_;
361 if (len > available) {
362 return false;
363 }
364 memcpy(credential_buffer_.get() + credential_buffer_length_,
365 credential_data, len);
366 credential_buffer_length_ += len;
367 return true;
368 }
369
370 // Convenience function which runs a framer simulation with particular input.
371 void SimulateInFramer(const unsigned char* input, size_t size) {
372 framer_.set_enable_compression(use_compression_);
373 framer_.set_visitor(this);
374 size_t input_remaining = size;
375 const char* input_ptr = reinterpret_cast<const char*>(input);
376 while (input_remaining > 0 &&
377 framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) {
378 // To make the tests more interesting, we feed random (amd small) chunks
379 // into the framer. This simulates getting strange-sized reads from
380 // the socket.
381 const size_t kMaxReadSize = 32;
382 size_t bytes_read =
383 (rand() % std::min(input_remaining, kMaxReadSize)) + 1;
384 size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read);
385 input_remaining -= bytes_processed;
386 input_ptr += bytes_processed;
387 if (framer_.state() == SpdyFramer::SPDY_DONE)
388 framer_.Reset();
389 }
390 }
391
392 void InitHeaderStreaming(const SpdyControlFrame* frame) {
393 memset(header_buffer_.get(), 0, header_buffer_size_);
394 header_buffer_length_ = 0;
395 header_stream_id_ = SpdyFramer::GetControlFrameStreamId(frame);
396 header_control_type_ = frame->type();
397 header_buffer_valid_ = true;
398 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
399 }
400
401 // Override the default buffer size (16K). Call before using the framer!
402 void set_header_buffer_size(size_t header_buffer_size) {
403 header_buffer_size_ = header_buffer_size;
404 header_buffer_.reset(new char[header_buffer_size]);
405 }
406
407 static size_t control_frame_buffer_max_size() {
408 return SpdyFramer::kControlFrameBufferMaxSize;
409 }
410
411 static size_t header_data_chunk_max_size() {
412 return SpdyFramer::kHeaderDataChunkMaxSize;
413 }
414
415 SpdyFramer framer_;
416 bool use_compression_;
417
418 // Counters from the visitor callbacks.
419 int error_count_;
420 int syn_frame_count_;
421 int syn_reply_frame_count_;
422 int headers_frame_count_;
423 int goaway_count_;
424 int credential_count_;
425 int settings_frame_count_;
426 int setting_count_;
427 int data_bytes_;
428 int fin_frame_count_; // The count of RST_STREAM type frames received.
429 int fin_flag_count_; // The count of frames with the FIN flag set.
430 int zero_length_data_frame_count_; // The count of zero-length data frames.
431 int header_blocks_count_;
432 int control_frame_header_data_count_; // The count of chunks received.
433 // The count of zero-length control frame header data chunks received.
434 int zero_length_control_frame_header_data_count_;
435 int data_frame_count_;
436
437 // Header block streaming state:
438 scoped_array<char> header_buffer_;
439 size_t header_buffer_length_;
440 size_t header_buffer_size_;
441 SpdyStreamId header_stream_id_;
442 SpdyControlType header_control_type_;
443 bool header_buffer_valid_;
444 SpdyHeaderBlock headers_;
445
446 scoped_array<char> credential_buffer_;
447 size_t credential_buffer_length_;
448 size_t credential_buffer_size_;
449 SpdyCredential credential_;
450 };
451
452 } // namespace test_spdy3
453
454 } // namespace spdy
455
456 using spdy::SpdyControlFlags;
457 using spdy::SpdyControlFrame;
458 using spdy::SpdyDataFrame;
459 using spdy::SpdyFrame;
460 using spdy::SpdyFrameBuilder;
461 using spdy::SpdyFramer;
462 using spdy::SpdyHeaderBlock;
463 using spdy::SpdySynStreamControlFrame;
464 using spdy::kControlFlagMask;
465 using spdy::kLengthMask;
466 using spdy::CONTROL_FLAG_NONE;
467 using spdy::DATA_FLAG_COMPRESSED;
468 using spdy::DATA_FLAG_FIN;
469 using spdy::SYN_STREAM;
470 using spdy::test_spdy3::CompareCharArraysWithHexError;
471 using spdy::test_spdy3::SpdyFramerTestUtil;
472 using spdy::test_spdy3::TestSpdyVisitor;
473
474 namespace spdy {
475
476 TEST(SpdyFrameBuilderSpdy3Test, WriteLimits) {
477 SpdyFrameBuilder builder(kLengthMask + 4);
478 // length field should fail.
479 EXPECT_FALSE(builder.WriteBytes(reinterpret_cast<const void*>(0x1),
480 kLengthMask + 1));
481 EXPECT_EQ(0, builder.length());
482
483 // Writing a block of the maximum allowed size should succeed.
484 const std::string kLargeData(kLengthMask, 'A');
485 builder.WriteUInt32(kLengthMask);
486 EXPECT_EQ(4, builder.length());
487 EXPECT_TRUE(builder.WriteBytes(kLargeData.data(), kLengthMask));
488 EXPECT_EQ(4 + kLengthMask, static_cast<unsigned>(builder.length()));
489 }
490
491 class SpdyFramerSpdy3Test : public PlatformTest {
492 public:
493 virtual void TearDown() {}
494
495 protected:
496 void CompareFrame(const std::string& description,
497 const SpdyFrame& actual_frame,
498 const unsigned char* expected,
499 const int expected_len) {
500 const unsigned char* actual =
501 reinterpret_cast<const unsigned char*>(actual_frame.data());
502 int actual_len = actual_frame.length() + SpdyFrame::kHeaderSize;
503 CompareCharArraysWithHexError(
504 description, actual, actual_len, expected, expected_len);
505 }
506
507 // Returns true if the two header blocks have equivalent content.
508 bool CompareHeaderBlocks(const SpdyHeaderBlock* expected,
509 const SpdyHeaderBlock* actual) {
510 if (expected->size() != actual->size()) {
511 LOG(ERROR) << "Expected " << expected->size() << " headers; actually got "
512 << actual->size() << "." << std::endl;
513 return false;
514 }
515 for (SpdyHeaderBlock::const_iterator it = expected->begin();
516 it != expected->end();
517 ++it) {
518 SpdyHeaderBlock::const_iterator it2 = actual->find(it->first);
519 if (it2 == actual->end()) {
520 LOG(ERROR) << "Expected header name '" << it->first << "'."
521 << std::endl;
522 return false;
523 }
524 if (it->second.compare(it2->second) != 0) {
525 LOG(ERROR) << "Expected header named '" << it->first
526 << "' to have a value of '" << it->second
527 << "'. The actual value received was '" << it2->second
528 << "'." << std::endl;
529 return false;
530 }
531 }
532 return true;
533 }
534 };
535
536
537 // Test that we can encode and decode a SpdyHeaderBlock in serialized form.
538 TEST_F(SpdyFramerSpdy3Test, HeaderBlockInBuffer) {
539 SpdyHeaderBlock headers;
540 headers["alpha"] = "beta";
541 headers["gamma"] = "charlie";
542 SpdyFramer framer(kVer);
543
544 // Encode the header block into a SynStream frame.
545 scoped_ptr<SpdySynStreamControlFrame> frame(
546 framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false, &headers));
547 EXPECT_TRUE(frame.get() != NULL);
548 std::string serialized_headers(frame->header_block(),
549 frame->header_block_len());
550 SpdyHeaderBlock new_headers;
551 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(),
552 serialized_headers.size(),
553 &new_headers));
554
555 EXPECT_EQ(headers.size(), new_headers.size());
556 EXPECT_EQ(headers["alpha"], new_headers["alpha"]);
557 EXPECT_EQ(headers["gamma"], new_headers["gamma"]);
558 }
559
560 // Test that if there's not a full frame, we fail to parse it.
561 TEST_F(SpdyFramerSpdy3Test, UndersizedHeaderBlockInBuffer) {
562 SpdyHeaderBlock headers;
563 headers["alpha"] = "beta";
564 headers["gamma"] = "charlie";
565 SpdyFramer framer(kVer);
566
567 // Encode the header block into a SynStream frame.
568 scoped_ptr<SpdySynStreamControlFrame> frame(
569 framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false, &headers));
570 EXPECT_TRUE(frame.get() != NULL);
571
572 std::string serialized_headers(frame->header_block(),
573 frame->header_block_len());
574 SpdyHeaderBlock new_headers;
575 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(),
576 serialized_headers.size() - 2,
577 &new_headers));
578 }
579
580 TEST_F(SpdyFramerSpdy3Test, OutOfOrderHeaders) {
581 // Frame builder with plentiful buffer size.
582 SpdyFrameBuilder frame(1024);
583
584 frame.WriteUInt16(kControlFlagMask | 1);
585 frame.WriteUInt16(SYN_STREAM);
586 frame.WriteUInt32(0); // Placeholder for the length.
587 frame.WriteUInt32(3); // stream_id
588 frame.WriteUInt32(0); // Associated stream id
589 frame.WriteUInt16(0); // Priority.
590
591 if (SPDY_VERSION_FOR_TESTS < 3) {
592 frame.WriteUInt16(2); // Number of headers.
593 frame.WriteString("gamma");
594 frame.WriteString("gamma");
595 frame.WriteString("alpha");
596 frame.WriteString("alpha");
597 } else {
598 frame.WriteUInt32(2); // Number of headers.
599 frame.WriteStringPiece32("gamma");
600 frame.WriteStringPiece32("gamma");
601 frame.WriteStringPiece32("alpha");
602 frame.WriteStringPiece32("alpha");
603 }
604 // write the length
605 frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize);
606
607 SpdyHeaderBlock new_headers;
608 scoped_ptr<SpdyFrame> control_frame(frame.take());
609 SpdySynStreamControlFrame syn_frame(control_frame->data(), false);
610 std::string serialized_headers(syn_frame.header_block(),
611 syn_frame.header_block_len());
612 SpdyFramer framer(kVer);
613 framer.set_enable_compression(false);
614 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(),
615 serialized_headers.size(),
616 &new_headers));
617 }
618
619 TEST_F(SpdyFramerSpdy3Test, CreateCredential) {
620 SpdyFramer framer(kVer);
621
622 {
623 const char kDescription[] = "CREDENTIAL frame";
624 const unsigned char kFrameData[] = {
625 0x80, kVer, 0x00, 0x0A,
626 0x00, 0x00, 0x00, 0x33,
627 0x00, 0x03, 0x00, 0x00,
628 0x00, 0x05, 'p', 'r',
629 'o', 'o', 'f', 0x00,
630 0x00, 0x00, 0x06, 'a',
631 ' ', 'c', 'e', 'r',
632 't', 0x00, 0x00, 0x00,
633 0x0C, 'a', 'n', 'o',
634 't', 'h', 'e', 'r',
635 ' ', 'c', 'e', 'r',
636 't', 0x00, 0x00, 0x00,
637 0x0A, 'f', 'i', 'n',
638 'a', 'l', ' ', 'c',
639 'e', 'r', 't',
640 };
641 SpdyCredential credential;
642 credential.slot = 3;
643 credential.proof = "proof";
644 credential.certs.push_back("a cert");
645 credential.certs.push_back("another cert");
646 credential.certs.push_back("final cert");
647 scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential));
648 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
649 }
650 }
651
652 TEST_F(SpdyFramerSpdy3Test, ParseCredentialFrameData) {
653 SpdyFramer framer(kVer);
654
655 {
656 unsigned char kFrameData[] = {
657 0x80, kVer, 0x00, 0x0A,
658 0x00, 0x00, 0x00, 0x33,
659 0x00, 0x03, 0x00, 0x00,
660 0x00, 0x05, 'p', 'r',
661 'o', 'o', 'f', 0x00,
662 0x00, 0x00, 0x06, 'a',
663 ' ', 'c', 'e', 'r',
664 't', 0x00, 0x00, 0x00,
665 0x0C, 'a', 'n', 'o',
666 't', 'h', 'e', 'r',
667 ' ', 'c', 'e', 'r',
668 't', 0x00, 0x00, 0x00,
669 0x0A, 'f', 'i', 'n',
670 'a', 'l', ' ', 'c',
671 'e', 'r', 't',
672 };
673 SpdyCredentialControlFrame frame(reinterpret_cast<char*>(kFrameData),
674 false);
675 SpdyCredential credential;
676 EXPECT_TRUE(SpdyFramer::ParseCredentialData(frame.payload(), frame.length(),
677 &credential));
678 EXPECT_EQ(3u, credential.slot);
679 EXPECT_EQ("proof", credential.proof);
680 EXPECT_EQ("a cert", credential.certs.front());
681 credential.certs.erase(credential.certs.begin());
682 EXPECT_EQ("another cert", credential.certs.front());
683 credential.certs.erase(credential.certs.begin());
684 EXPECT_EQ("final cert", credential.certs.front());
685 credential.certs.erase(credential.certs.begin());
686 EXPECT_TRUE(credential.certs.empty());
687 }
688 }
689
690 TEST_F(SpdyFramerSpdy3Test, DuplicateHeader) {
691 // Frame builder with plentiful buffer size.
692 SpdyFrameBuilder frame(1024);
693
694 frame.WriteUInt16(kControlFlagMask | 1);
695 frame.WriteUInt16(SYN_STREAM);
696 frame.WriteUInt32(0); // Placeholder for the length.
697 frame.WriteUInt32(3); // stream_id
698 frame.WriteUInt32(0); // associated stream id
699 frame.WriteUInt16(0); // Priority.
700
701 if (SPDY_VERSION_FOR_TESTS < 3) {
702 frame.WriteUInt16(2); // Number of headers.
703 frame.WriteString("name");
704 frame.WriteString("value1");
705 frame.WriteString("name");
706 frame.WriteString("value2");
707 } else {
708 frame.WriteUInt32(2); // Number of headers.
709 frame.WriteStringPiece32("name");
710 frame.WriteStringPiece32("value1");
711 frame.WriteStringPiece32("name");
712 frame.WriteStringPiece32("value2");
713 }
714 // write the length
715 frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize);
716
717 SpdyHeaderBlock new_headers;
718 scoped_ptr<SpdyFrame> control_frame(frame.take());
719 SpdySynStreamControlFrame syn_frame(control_frame->data(), false);
720 std::string serialized_headers(syn_frame.header_block(),
721 syn_frame.header_block_len());
722 SpdyFramer framer(kVer);
723 framer.set_enable_compression(false);
724 // This should fail because duplicate headers are verboten by the spec.
725 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(),
726 serialized_headers.size(),
727 &new_headers));
728 }
729
730 TEST_F(SpdyFramerSpdy3Test, MultiValueHeader) {
731 // Frame builder with plentiful buffer size.
732 SpdyFrameBuilder frame(1024);
733
734 frame.WriteUInt16(kControlFlagMask | 1);
735 frame.WriteUInt16(SYN_STREAM);
736 frame.WriteUInt32(0); // Placeholder for the length.
737 frame.WriteUInt32(3); // stream_id
738 frame.WriteUInt32(0); // associated stream id
739 frame.WriteUInt16(0); // Priority.
740
741 std::string value("value1\0value2");
742 if (SPDY_VERSION_FOR_TESTS < 3) {
743 frame.WriteUInt16(1); // Number of headers.
744 frame.WriteString("name");
745 frame.WriteString(value);
746 } else {
747 frame.WriteUInt32(1); // Number of headers.
748 frame.WriteStringPiece32("name");
749 frame.WriteStringPiece32(value);
750 }
751 // write the length
752 frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize);
753
754 SpdyHeaderBlock new_headers;
755 scoped_ptr<SpdyFrame> control_frame(frame.take());
756 SpdySynStreamControlFrame syn_frame(control_frame->data(), false);
757 std::string serialized_headers(syn_frame.header_block(),
758 syn_frame.header_block_len());
759 SpdyFramer framer(kVer);
760 framer.set_enable_compression(false);
761 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(),
762 serialized_headers.size(),
763 &new_headers));
764 EXPECT_TRUE(new_headers.find("name") != new_headers.end());
765 EXPECT_EQ(value, new_headers.find("name")->second);
766 }
767
768 TEST_F(SpdyFramerSpdy3Test, BasicCompression) {
769 SpdyHeaderBlock headers;
770 headers["server"] = "SpdyServer 1.0";
771 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST";
772 headers["status"] = "200";
773 headers["version"] = "HTTP/1.1";
774 headers["content-type"] = "text/html";
775 headers["content-length"] = "12";
776
777 SpdyFramer framer(kVer);
778 framer.set_enable_compression(true);
779 scoped_ptr<SpdySynStreamControlFrame>
780 frame1(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true,
781 &headers));
782 scoped_ptr<SpdySynStreamControlFrame>
783 frame2(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true,
784 &headers));
785
786 // Expect the second frame to be more compact than the first.
787 EXPECT_LE(frame2->length(), frame1->length());
788
789 // Decompress the first frame
790 scoped_ptr<SpdyFrame> frame3(SpdyFramerTestUtil::DecompressFrame(
791 &framer, *frame1.get()));
792
793 // Decompress the second frame
794 scoped_ptr<SpdyFrame> frame4(SpdyFramerTestUtil::DecompressFrame(
795 &framer, *frame2.get()));
796
797 // Expect frames 3 & 4 to be the same.
798 EXPECT_EQ(0,
799 memcmp(frame3->data(), frame4->data(),
800 SpdyFrame::kHeaderSize + frame3->length()));
801
802
803 // Expect frames 3 to be the same as a uncompressed frame created
804 // from scratch.
805 scoped_ptr<SpdySynStreamControlFrame>
806 uncompressed_frame(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE,
807 false, &headers));
808 EXPECT_EQ(frame3->length(), uncompressed_frame->length());
809 EXPECT_EQ(0,
810 memcmp(frame3->data(), uncompressed_frame->data(),
811 SpdyFrame::kHeaderSize + uncompressed_frame->length()));
812 }
813
814 TEST_F(SpdyFramerSpdy3Test, Basic) {
815 const unsigned char kV2Input[] = {
816 0x80, kVer, 0x00, 0x01, // SYN Stream #1
817 0x00, 0x00, 0x00, 0x14,
818 0x00, 0x00, 0x00, 0x01,
819 0x00, 0x00, 0x00, 0x00,
820 0x00, 0x00, 0x00, 0x01,
821 0x00, 0x02, 'h', 'h',
822 0x00, 0x02, 'v', 'v',
823
824 0x80, kVer, 0x00, 0x08, // HEADERS on Stream #1
825 0x00, 0x00, 0x00, 0x18,
826 0x00, 0x00, 0x00, 0x01,
827 0x00, 0x00, 0x00, 0x02,
828 0x00, 0x02, 'h', '2',
829 0x00, 0x02, 'v', '2',
830 0x00, 0x02, 'h', '3',
831 0x00, 0x02, 'v', '3',
832
833 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
834 0x00, 0x00, 0x00, 0x0c,
835 0xde, 0xad, 0xbe, 0xef,
836 0xde, 0xad, 0xbe, 0xef,
837 0xde, 0xad, 0xbe, 0xef,
838
839 0x80, kVer, 0x00, 0x01, // SYN Stream #3
840 0x00, 0x00, 0x00, 0x0c,
841 0x00, 0x00, 0x00, 0x03,
842 0x00, 0x00, 0x00, 0x00,
843 0x00, 0x00, 0x00, 0x00,
844
845 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
846 0x00, 0x00, 0x00, 0x08,
847 0xde, 0xad, 0xbe, 0xef,
848 0xde, 0xad, 0xbe, 0xef,
849
850 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
851 0x00, 0x00, 0x00, 0x04,
852 0xde, 0xad, 0xbe, 0xef,
853
854 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #1
855 0x00, 0x00, 0x00, 0x08,
856 0x00, 0x00, 0x00, 0x01,
857 0x00, 0x00, 0x00, 0x00,
858
859 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
860 0x00, 0x00, 0x00, 0x00,
861
862 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #3
863 0x00, 0x00, 0x00, 0x08,
864 0x00, 0x00, 0x00, 0x03,
865 0x00, 0x00, 0x00, 0x00,
866 };
867
868 const unsigned char kV3Input[] = {
869 0x80, kVer, 0x00, 0x01, // SYN Stream #1
870 0x00, 0x00, 0x00, 0x1a,
871 0x00, 0x00, 0x00, 0x01,
872 0x00, 0x00, 0x00, 0x00,
873 0x00, 0x00, 0x00, 0x00,
874 0x00, 0x01, 0x00, 0x00,
875 0x00, 0x02, 'h', 'h',
876 0x00, 0x00, 0x00, 0x02,
877 'v', 'v',
878
879 0x80, kVer, 0x00, 0x08, // HEADERS on Stream #1
880 0x00, 0x00, 0x00, 0x22,
881 0x00, 0x00, 0x00, 0x01,
882 0x00, 0x00, 0x00, 0x00,
883 0x00, 0x02, 0x00, 0x00,
884 0x00, 0x02, 'h', '2',
885 0x00, 0x00, 0x00, 0x02,
886 'v', '2', 0x00, 0x00,
887 0x00, 0x02, 'h', '3',
888 0x00, 0x00, 0x00, 0x02,
889 'v', '3',
890
891 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
892 0x00, 0x00, 0x00, 0x0c,
893 0xde, 0xad, 0xbe, 0xef,
894 0xde, 0xad, 0xbe, 0xef,
895 0xde, 0xad, 0xbe, 0xef,
896
897 0x80, kVer, 0x00, 0x01, // SYN Stream #3
898 0x00, 0x00, 0x00, 0x0e,
899 0x00, 0x00, 0x00, 0x03,
900 0x00, 0x00, 0x00, 0x00,
901 0x00, 0x00, 0x00, 0x00,
902 0x00, 0x00,
903
904 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
905 0x00, 0x00, 0x00, 0x08,
906 0xde, 0xad, 0xbe, 0xef,
907 0xde, 0xad, 0xbe, 0xef,
908
909 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
910 0x00, 0x00, 0x00, 0x04,
911 0xde, 0xad, 0xbe, 0xef,
912
913 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #1
914 0x00, 0x00, 0x00, 0x08,
915 0x00, 0x00, 0x00, 0x01,
916 0x00, 0x00, 0x00, 0x00,
917
918 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
919 0x00, 0x00, 0x00, 0x00,
920
921 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #3
922 0x00, 0x00, 0x00, 0x08,
923 0x00, 0x00, 0x00, 0x03,
924 0x00, 0x00, 0x00, 0x00,
925 };
926
927 TestSpdyVisitor visitor;
928 if (SPDY_VERSION_FOR_TESTS < 3) {
929 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
930 } else {
931 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
932 }
933
934 EXPECT_EQ(0, visitor.error_count_);
935 EXPECT_EQ(2, visitor.syn_frame_count_);
936 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
937 EXPECT_EQ(1, visitor.headers_frame_count_);
938 EXPECT_EQ(24, visitor.data_bytes_);
939 EXPECT_EQ(2, visitor.fin_frame_count_);
940 EXPECT_EQ(0, visitor.fin_flag_count_);
941 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
942 EXPECT_EQ(4, visitor.data_frame_count_);
943 }
944
945 // Test that the FIN flag on a data frame signifies EOF.
946 TEST_F(SpdyFramerSpdy3Test, FinOnDataFrame) {
947 const unsigned char kV2Input[] = {
948 0x80, kVer, 0x00, 0x01, // SYN Stream #1
949 0x00, 0x00, 0x00, 0x14,
950 0x00, 0x00, 0x00, 0x01,
951 0x00, 0x00, 0x00, 0x00,
952 0x00, 0x00, 0x00, 0x01,
953 0x00, 0x02, 'h', 'h',
954 0x00, 0x02, 'v', 'v',
955
956 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1
957 0x00, 0x00, 0x00, 0x10,
958 0x00, 0x00, 0x00, 0x01,
959 0x00, 0x00, 0x00, 0x01,
960 0x00, 0x02, 'a', 'a',
961 0x00, 0x02, 'b', 'b',
962
963 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
964 0x00, 0x00, 0x00, 0x0c,
965 0xde, 0xad, 0xbe, 0xef,
966 0xde, 0xad, 0xbe, 0xef,
967 0xde, 0xad, 0xbe, 0xef,
968
969 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF
970 0x01, 0x00, 0x00, 0x04,
971 0xde, 0xad, 0xbe, 0xef,
972 };
973 const unsigned char kV3Input[] = {
974 0x80, kVer, 0x00, 0x01, // SYN Stream #1
975 0x00, 0x00, 0x00, 0x1a,
976 0x00, 0x00, 0x00, 0x01,
977 0x00, 0x00, 0x00, 0x00,
978 0x00, 0x00, 0x00, 0x00,
979 0x00, 0x01, 0x00, 0x00,
980 0x00, 0x02, 'h', 'h',
981 0x00, 0x00, 0x00, 0x02,
982 'v', 'v',
983
984 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1
985 0x00, 0x00, 0x00, 0x16,
986 0x00, 0x00, 0x00, 0x01,
987 0x00, 0x00, 0x00, 0x00,
988 0x00, 0x01, 0x00, 0x00,
989 0x00, 0x02, 'a', 'a',
990 0x00, 0x00, 0x00, 0x02,
991 'b', 'b',
992
993 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
994 0x00, 0x00, 0x00, 0x0c,
995 0xde, 0xad, 0xbe, 0xef,
996 0xde, 0xad, 0xbe, 0xef,
997 0xde, 0xad, 0xbe, 0xef,
998
999 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF
1000 0x01, 0x00, 0x00, 0x04,
1001 0xde, 0xad, 0xbe, 0xef,
1002 };
1003
1004 TestSpdyVisitor visitor;
1005 if (SPDY_VERSION_FOR_TESTS < 3) {
1006 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
1007 } else {
1008 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
1009 }
1010
1011 EXPECT_EQ(0, visitor.error_count_);
1012 EXPECT_EQ(1, visitor.syn_frame_count_);
1013 EXPECT_EQ(1, visitor.syn_reply_frame_count_);
1014 EXPECT_EQ(0, visitor.headers_frame_count_);
1015 EXPECT_EQ(16, visitor.data_bytes_);
1016 EXPECT_EQ(0, visitor.fin_frame_count_);
1017 EXPECT_EQ(0, visitor.fin_flag_count_);
1018 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1019 EXPECT_EQ(2, visitor.data_frame_count_);
1020 }
1021
1022 // Test that the FIN flag on a SYN reply frame signifies EOF.
1023 TEST_F(SpdyFramerSpdy3Test, FinOnSynReplyFrame) {
1024 const unsigned char kV2Input[] = {
1025 0x80, kVer, 0x00, 0x01, // SYN Stream #1
1026 0x00, 0x00, 0x00, 0x14,
1027 0x00, 0x00, 0x00, 0x01,
1028 0x00, 0x00, 0x00, 0x00,
1029 0x00, 0x00, 0x00, 0x01,
1030 0x00, 0x02, 'h', 'h',
1031 0x00, 0x02, 'v', 'v',
1032
1033 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1
1034 0x01, 0x00, 0x00, 0x14,
1035 0x00, 0x00, 0x00, 0x01,
1036 0x00, 0x00, 0x00, 0x00,
1037 0x00, 0x00, 0x00, 0x01,
1038 0x00, 0x02, 'a', 'a',
1039 0x00, 0x02, 'b', 'b',
1040 };
1041 const unsigned char kV3Input[] = {
1042 0x80, kVer, 0x00, 0x01, // SYN Stream #1
1043 0x00, 0x00, 0x00, 0x1a,
1044 0x00, 0x00, 0x00, 0x01,
1045 0x00, 0x00, 0x00, 0x00,
1046 0x00, 0x00, 0x00, 0x00,
1047 0x00, 0x01, 0x00, 0x00,
1048 0x00, 0x02, 'h', 'h',
1049 0x00, 0x00, 0x00, 0x02,
1050 'v', 'v',
1051
1052 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1
1053 0x01, 0x00, 0x00, 0x1a,
1054 0x00, 0x00, 0x00, 0x01,
1055 0x00, 0x00, 0x00, 0x00,
1056 0x00, 0x00, 0x00, 0x00,
1057 0x00, 0x01, 0x00, 0x00,
1058 0x00, 0x02, 'a', 'a',
1059 0x00, 0x00, 0x00, 0x02,
1060 'b', 'b',
1061 };
1062
1063 TestSpdyVisitor visitor;
1064 if (SPDY_VERSION_FOR_TESTS < 3) {
1065 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
1066 } else {
1067 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
1068 }
1069
1070 EXPECT_EQ(0, visitor.error_count_);
1071 EXPECT_EQ(1, visitor.syn_frame_count_);
1072 EXPECT_EQ(1, visitor.syn_reply_frame_count_);
1073 EXPECT_EQ(0, visitor.headers_frame_count_);
1074 EXPECT_EQ(0, visitor.data_bytes_);
1075 EXPECT_EQ(0, visitor.fin_frame_count_);
1076 EXPECT_EQ(1, visitor.fin_flag_count_);
1077 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1078 EXPECT_EQ(0, visitor.data_frame_count_);
1079 }
1080
1081 TEST_F(SpdyFramerSpdy3Test, HeaderCompression) {
1082 SpdyFramer send_framer(kVer);
1083 SpdyFramer recv_framer(kVer);
1084
1085 send_framer.set_enable_compression(true);
1086 recv_framer.set_enable_compression(true);
1087
1088 const char kHeader1[] = "header1";
1089 const char kHeader2[] = "header2";
1090 const char kHeader3[] = "header3";
1091 const char kValue1[] = "value1";
1092 const char kValue2[] = "value2";
1093 const char kValue3[] = "value3";
1094
1095 // SYN_STREAM #1
1096 SpdyHeaderBlock block;
1097 block[kHeader1] = kValue1;
1098 block[kHeader2] = kValue2;
1099 SpdyControlFlags flags(CONTROL_FLAG_NONE);
1100 scoped_ptr<SpdySynStreamControlFrame> syn_frame_1(
1101 send_framer.CreateSynStream(1, 0, 0, flags, true, &block));
1102 EXPECT_TRUE(syn_frame_1.get() != NULL);
1103
1104 // SYN_STREAM #2
1105 block[kHeader3] = kValue3;
1106 scoped_ptr<SpdySynStreamControlFrame> syn_frame_2(
1107 send_framer.CreateSynStream(3, 0, 0, flags, true, &block));
1108 EXPECT_TRUE(syn_frame_2.get() != NULL);
1109
1110 // Now start decompressing
1111 scoped_ptr<SpdyFrame> decompressed;
1112 scoped_ptr<SpdySynStreamControlFrame> syn_frame;
1113 scoped_ptr<std::string> serialized_headers;
1114 SpdyHeaderBlock decompressed_headers;
1115
1116 // Decompress SYN_STREAM #1
1117 decompressed.reset(SpdyFramerTestUtil::DecompressFrame(
1118 &recv_framer, *syn_frame_1.get()));
1119 EXPECT_TRUE(decompressed.get() != NULL);
1120 EXPECT_TRUE(decompressed->is_control_frame());
1121 EXPECT_EQ(SYN_STREAM,
1122 reinterpret_cast<SpdyControlFrame*>(decompressed.get())->type());
1123 syn_frame.reset(new SpdySynStreamControlFrame(decompressed->data(), false));
1124 serialized_headers.reset(new std::string(syn_frame->header_block(),
1125 syn_frame->header_block_len()));
1126 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers->c_str(),
1127 serialized_headers->size(),
1128 &decompressed_headers));
1129 EXPECT_EQ(2u, decompressed_headers.size());
1130 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
1131 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
1132
1133 // Decompress SYN_STREAM #2
1134 decompressed.reset(SpdyFramerTestUtil::DecompressFrame(
1135 &recv_framer, *syn_frame_2.get()));
1136 EXPECT_TRUE(decompressed.get() != NULL);
1137 EXPECT_TRUE(decompressed->is_control_frame());
1138 EXPECT_EQ(SYN_STREAM,
1139 reinterpret_cast<SpdyControlFrame*>(decompressed.get())->type());
1140 syn_frame.reset(new SpdySynStreamControlFrame(decompressed->data(), false));
1141 serialized_headers.reset(new std::string(syn_frame->header_block(),
1142 syn_frame->header_block_len()));
1143 decompressed_headers.clear();
1144 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers->c_str(),
1145 serialized_headers->size(),
1146 &decompressed_headers));
1147 EXPECT_EQ(3u, decompressed_headers.size());
1148 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
1149 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
1150 EXPECT_EQ(kValue3, decompressed_headers[kHeader3]);
1151
1152 // We didn't have data streams, so we shouldn't have (de)compressors.
1153 EXPECT_EQ(0, send_framer.num_stream_compressors());
1154 EXPECT_EQ(0, send_framer.num_stream_decompressors());
1155 EXPECT_EQ(0, recv_framer.num_stream_compressors());
1156 EXPECT_EQ(0, recv_framer.num_stream_decompressors());
1157 }
1158
1159 // Verify we don't leak when we leave streams unclosed
1160 TEST_F(SpdyFramerSpdy3Test, UnclosedStreamDataCompressors) {
1161 SpdyFramer send_framer(kVer);
1162
1163 send_framer.set_enable_compression(true);
1164
1165 const char kHeader1[] = "header1";
1166 const char kHeader2[] = "header2";
1167 const char kValue1[] = "value1";
1168 const char kValue2[] = "value2";
1169
1170 SpdyHeaderBlock block;
1171 block[kHeader1] = kValue1;
1172 block[kHeader2] = kValue2;
1173 SpdyControlFlags flags(CONTROL_FLAG_NONE);
1174 scoped_ptr<SpdyFrame> syn_frame(
1175 send_framer.CreateSynStream(1, 0, 0, flags, true, &block));
1176 EXPECT_TRUE(syn_frame.get() != NULL);
1177
1178 const char bytes[] = "this is a test test test test test!";
1179 scoped_ptr<SpdyFrame> send_frame(
1180 send_framer.CreateDataFrame(
1181 1, bytes, arraysize(bytes),
1182 static_cast<SpdyDataFlags>(DATA_FLAG_FIN)));
1183 EXPECT_TRUE(send_frame.get() != NULL);
1184
1185 // Run the inputs through the framer.
1186 TestSpdyVisitor visitor;
1187 visitor.use_compression_ = true;
1188 const unsigned char* data;
1189 data = reinterpret_cast<const unsigned char*>(syn_frame->data());
1190 visitor.SimulateInFramer(data, syn_frame->length() + SpdyFrame::kHeaderSize);
1191 data = reinterpret_cast<const unsigned char*>(send_frame->data());
1192 visitor.SimulateInFramer(data, send_frame->length() + SpdyFrame::kHeaderSize);
1193
1194 EXPECT_EQ(0, visitor.error_count_);
1195 EXPECT_EQ(1, visitor.syn_frame_count_);
1196 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1197 EXPECT_EQ(0, visitor.headers_frame_count_);
1198 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_));
1199 EXPECT_EQ(0, visitor.fin_frame_count_);
1200 EXPECT_EQ(0, visitor.fin_flag_count_);
1201 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1202 EXPECT_EQ(1, visitor.data_frame_count_);
1203
1204 // We closed the streams, so all compressors should be down.
1205 EXPECT_EQ(0, visitor.framer_.num_stream_compressors());
1206 EXPECT_EQ(0, visitor.framer_.num_stream_decompressors());
1207 EXPECT_EQ(0, send_framer.num_stream_compressors());
1208 EXPECT_EQ(0, send_framer.num_stream_decompressors());
1209 }
1210
1211 // Verify we can decompress the stream even if handed over to the
1212 // framer 1 byte at a time.
1213 TEST_F(SpdyFramerSpdy3Test, UnclosedStreamDataCompressorsOneByteAtATime) {
1214 SpdyFramer send_framer(kVer);
1215
1216 send_framer.set_enable_compression(true);
1217
1218 const char kHeader1[] = "header1";
1219 const char kHeader2[] = "header2";
1220 const char kValue1[] = "value1";
1221 const char kValue2[] = "value2";
1222
1223 SpdyHeaderBlock block;
1224 block[kHeader1] = kValue1;
1225 block[kHeader2] = kValue2;
1226 SpdyControlFlags flags(CONTROL_FLAG_NONE);
1227 scoped_ptr<SpdyFrame> syn_frame(
1228 send_framer.CreateSynStream(1, 0, 0, flags, true, &block));
1229 EXPECT_TRUE(syn_frame.get() != NULL);
1230
1231 const char bytes[] = "this is a test test test test test!";
1232 scoped_ptr<SpdyFrame> send_frame(
1233 send_framer.CreateDataFrame(
1234 1, bytes, arraysize(bytes),
1235 static_cast<SpdyDataFlags>(DATA_FLAG_FIN)));
1236 EXPECT_TRUE(send_frame.get() != NULL);
1237
1238 // Run the inputs through the framer.
1239 TestSpdyVisitor visitor;
1240 visitor.use_compression_ = true;
1241 const unsigned char* data;
1242 data = reinterpret_cast<const unsigned char*>(syn_frame->data());
1243 for (size_t idx = 0;
1244 idx < syn_frame->length() + SpdyFrame::kHeaderSize;
1245 ++idx) {
1246 visitor.SimulateInFramer(data + idx, 1);
1247 ASSERT_EQ(0, visitor.error_count_);
1248 }
1249 data = reinterpret_cast<const unsigned char*>(send_frame->data());
1250 for (size_t idx = 0;
1251 idx < send_frame->length() + SpdyFrame::kHeaderSize;
1252 ++idx) {
1253 visitor.SimulateInFramer(data + idx, 1);
1254 ASSERT_EQ(0, visitor.error_count_);
1255 }
1256
1257 EXPECT_EQ(0, visitor.error_count_);
1258 EXPECT_EQ(1, visitor.syn_frame_count_);
1259 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1260 EXPECT_EQ(0, visitor.headers_frame_count_);
1261 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_));
1262 EXPECT_EQ(0, visitor.fin_frame_count_);
1263 EXPECT_EQ(0, visitor.fin_flag_count_);
1264 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1265 EXPECT_EQ(1, visitor.data_frame_count_);
1266
1267 // We closed the streams, so all compressors should be down.
1268 EXPECT_EQ(0, visitor.framer_.num_stream_compressors());
1269 EXPECT_EQ(0, visitor.framer_.num_stream_decompressors());
1270 EXPECT_EQ(0, send_framer.num_stream_compressors());
1271 EXPECT_EQ(0, send_framer.num_stream_decompressors());
1272 }
1273
1274 TEST_F(SpdyFramerSpdy3Test, WindowUpdateFrame) {
1275 SpdyFramer framer(kVer);
1276 scoped_ptr<SpdyWindowUpdateControlFrame> window_update_frame(
1277 framer.CreateWindowUpdate(1, 0x12345678));
1278
1279 const unsigned char expected_data_frame[] = {
1280 0x80, kVer, 0x00, 0x09,
1281 0x00, 0x00, 0x00, 0x08,
1282 0x00, 0x00, 0x00, 0x01,
1283 0x12, 0x34, 0x56, 0x78
1284 };
1285
1286 EXPECT_EQ(16u, window_update_frame->size());
1287 EXPECT_EQ(0,
1288 memcmp(window_update_frame->data(), expected_data_frame, 16));
1289 }
1290
1291 TEST_F(SpdyFramerSpdy3Test, CreateDataFrame) {
1292 SpdyFramer framer(kVer);
1293
1294 {
1295 const char kDescription[] = "'hello' data frame, no FIN";
1296 const unsigned char kFrameData[] = {
1297 0x00, 0x00, 0x00, 0x01,
1298 0x00, 0x00, 0x00, 0x05,
1299 'h', 'e', 'l', 'l',
1300 'o'
1301 };
1302 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1303 1, "hello", 5, DATA_FLAG_NONE));
1304 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1305 }
1306
1307 {
1308 const char kDescription[] = "Data frame with negative data byte, no FIN";
1309 const unsigned char kFrameData[] = {
1310 0x00, 0x00, 0x00, 0x01,
1311 0x00, 0x00, 0x00, 0x01,
1312 0xff
1313 };
1314 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1315 1, "\xff", 1, DATA_FLAG_NONE));
1316 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1317 }
1318
1319 {
1320 const char kDescription[] = "'hello' data frame, with FIN";
1321 const unsigned char kFrameData[] = {
1322 0x00, 0x00, 0x00, 0x01,
1323 0x01, 0x00, 0x00, 0x05,
1324 'h', 'e', 'l', 'l',
1325 'o'
1326 };
1327 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1328 1, "hello", 5, DATA_FLAG_FIN));
1329 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1330 }
1331
1332 {
1333 const char kDescription[] = "Empty data frame";
1334 const unsigned char kFrameData[] = {
1335 0x00, 0x00, 0x00, 0x01,
1336 0x00, 0x00, 0x00, 0x00,
1337 };
1338 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1339 1, "", 0, DATA_FLAG_NONE));
1340 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1341 }
1342
1343 {
1344 const char kDescription[] = "Data frame with max stream ID";
1345 const unsigned char kFrameData[] = {
1346 0x7f, 0xff, 0xff, 0xff,
1347 0x01, 0x00, 0x00, 0x05,
1348 'h', 'e', 'l', 'l',
1349 'o'
1350 };
1351 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1352 0x7fffffff, "hello", 5, DATA_FLAG_FIN));
1353 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1354 }
1355
1356 {
1357 const char kDescription[] = "Large data frame";
1358 const int kDataSize = 4 * 1024 * 1024; // 4 MB
1359 const std::string kData(kDataSize, 'A');
1360 const unsigned char kFrameHeader[] = {
1361 0x00, 0x00, 0x00, 0x01,
1362 0x01, 0x40, 0x00, 0x00,
1363 };
1364
1365 const int kFrameSize = arraysize(kFrameHeader) + kDataSize;
1366 scoped_array<unsigned char> expected_frame_data(
1367 new unsigned char[kFrameSize]);
1368 memcpy(expected_frame_data.get(), kFrameHeader, arraysize(kFrameHeader));
1369 memset(expected_frame_data.get() + arraysize(kFrameHeader), 'A', kDataSize);
1370
1371 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1372 1, kData.data(), kData.size(), DATA_FLAG_FIN));
1373 CompareFrame(kDescription, *frame, expected_frame_data.get(), kFrameSize);
1374 }
1375 }
1376
1377 TEST_F(SpdyFramerSpdy3Test, CreateSynStreamUncompressed) {
1378 SpdyFramer framer(kVer);
1379 framer.set_enable_compression(false);
1380
1381 {
1382 const char kDescription[] = "SYN_STREAM frame, lowest pri, no FIN";
1383
1384 SpdyHeaderBlock headers;
1385 headers["bar"] = "foo";
1386 headers["foo"] = "bar";
1387
1388 const unsigned char kPri =
1389 (SPDY_VERSION_FOR_TESTS != 2) ? 0xE0 : 0xC0;
1390 const unsigned char kV2FrameData[] = {
1391 0x80, kVer, 0x00, 0x01,
1392 0x00, 0x00, 0x00, 0x20,
1393 0x00, 0x00, 0x00, 0x01,
1394 0x00, 0x00, 0x00, 0x00,
1395 kPri, 0x00, 0x00, 0x02,
1396 0x00, 0x03, 'b', 'a',
1397 'r', 0x00, 0x03, 'f',
1398 'o', 'o', 0x00, 0x03,
1399 'f', 'o', 'o', 0x00,
1400 0x03, 'b', 'a', 'r'
1401 };
1402 const unsigned char kV3FrameData[] = {
1403 0x80, kVer, 0x00, 0x01,
1404 0x00, 0x00, 0x00, 0x2a,
1405 0x00, 0x00, 0x00, 0x01,
1406 0x00, 0x00, 0x00, 0x00,
1407 kPri, 0x00, 0x00, 0x00,
1408 0x00, 0x02, 0x00, 0x00,
1409 0x00, 0x03, 'b', 'a',
1410 'r', 0x00, 0x00, 0x00,
1411 0x03, 'f', 'o', 'o',
1412 0x00, 0x00, 0x00, 0x03,
1413 'f', 'o', 'o', 0x00,
1414 0x00, 0x00, 0x03, 'b',
1415 'a', 'r'
1416 };
1417 scoped_ptr<SpdySynStreamControlFrame> frame(framer.CreateSynStream(
1418 1, 0, framer.GetLowestPriority(), CONTROL_FLAG_NONE, false, &headers));
1419 CompareFrame(kDescription,
1420 *frame,
1421 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
1422 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
1423 : arraysize(kV3FrameData));
1424 EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get()));
1425 }
1426
1427 {
1428 const char kDescription[] =
1429 "SYN_STREAM frame with a 0-length header name, highest pri, FIN, "
1430 "max stream ID";
1431
1432 SpdyHeaderBlock headers;
1433 headers[""] = "foo";
1434 headers["foo"] = "bar";
1435
1436 const unsigned char kV2FrameData[] = {
1437 0x80, kVer, 0x00, 0x01,
1438 0x01, 0x00, 0x00, 0x1D,
1439 0x7f, 0xff, 0xff, 0xff,
1440 0x7f, 0xff, 0xff, 0xff,
1441 0x00, 0x00, 0x00, 0x02,
1442 0x00, 0x00, 0x00, 0x03,
1443 'f', 'o', 'o', 0x00,
1444 0x03, 'f', 'o', 'o',
1445 0x00, 0x03, 'b', 'a',
1446 'r'
1447 };
1448 const unsigned char kV3FrameData[] = {
1449 0x80, kVer, 0x00, 0x01,
1450 0x01, 0x00, 0x00, 0x27,
1451 0x7f, 0xff, 0xff, 0xff,
1452 0x7f, 0xff, 0xff, 0xff,
1453 0x00, 0x00, 0x00, 0x00,
1454 0x00, 0x02, 0x00, 0x00,
1455 0x00, 0x00, 0x00, 0x00,
1456 0x00, 0x03, 'f', 'o',
1457 'o', 0x00, 0x00, 0x00,
1458 0x03, 'f', 'o', 'o',
1459 0x00, 0x00, 0x00, 0x03,
1460 'b', 'a', 'r'
1461 };
1462 scoped_ptr<SpdyFrame> frame(framer.CreateSynStream(
1463 0x7fffffff, 0x7fffffff, framer.GetHighestPriority(), CONTROL_FLAG_FIN,
1464 false, &headers));
1465 CompareFrame(kDescription,
1466 *frame,
1467 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
1468 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
1469 : arraysize(kV3FrameData));
1470 }
1471
1472 {
1473 const char kDescription[] =
1474 "SYN_STREAM frame with a 0-length header val, high pri, FIN, "
1475 "max stream ID";
1476
1477 SpdyHeaderBlock headers;
1478 headers["bar"] = "foo";
1479 headers["foo"] = "";
1480
1481 const unsigned char kPri =
1482 (SPDY_VERSION_FOR_TESTS != 2) ? 0x20 : 0x40;
1483 const unsigned char kV2FrameData[] = {
1484 0x80, kVer, 0x00, 0x01,
1485 0x01, 0x00, 0x00, 0x1D,
1486 0x7f, 0xff, 0xff, 0xff,
1487 0x7f, 0xff, 0xff, 0xff,
1488 kPri, 0x00, 0x00, 0x02,
1489 0x00, 0x03, 'b', 'a',
1490 'r', 0x00, 0x03, 'f',
1491 'o', 'o', 0x00, 0x03,
1492 'f', 'o', 'o', 0x00,
1493 0x00
1494 };
1495 const unsigned char kV3FrameData[] = {
1496 0x80, kVer, 0x00, 0x01,
1497 0x01, 0x00, 0x00, 0x27,
1498 0x7f, 0xff, 0xff, 0xff,
1499 0x7f, 0xff, 0xff, 0xff,
1500 kPri, 0x00, 0x00, 0x00,
1501 0x00, 0x02, 0x00, 0x00,
1502 0x00, 0x03, 'b', 'a',
1503 'r', 0x00, 0x00, 0x00,
1504 0x03, 'f', 'o', 'o',
1505 0x00, 0x00, 0x00, 0x03,
1506 'f', 'o', 'o', 0x00,
1507 0x00, 0x00, 0x00
1508 };
1509 scoped_ptr<SpdyFrame> frame(framer.CreateSynStream(
1510 0x7fffffff, 0x7fffffff, 1, CONTROL_FLAG_FIN, false, &headers));
1511 CompareFrame(kDescription,
1512 *frame,
1513 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
1514 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
1515 : arraysize(kV3FrameData));
1516 }
1517 }
1518
1519 TEST_F(SpdyFramerSpdy3Test, CreateSynStreamCompressed) {
1520 SpdyFramer framer(kVer);
1521 framer.set_enable_compression(true);
1522
1523 {
1524 const char kDescription[] =
1525 "SYN_STREAM frame, low pri, no FIN";
1526
1527 SpdyHeaderBlock headers;
1528 headers["bar"] = "foo";
1529 headers["foo"] = "bar";
1530
1531 const SpdyPriority priority =
1532 (SPDY_VERSION_FOR_TESTS != 2) ? 4 : 2;
1533 const unsigned char kV2FrameData[] = {
1534 0x80, kVer, 0x00, 0x01,
1535 0x00, 0x00, 0x00, 0x25,
1536 0x00, 0x00, 0x00, 0x01,
1537 0x00, 0x00, 0x00, 0x00,
1538 0x80, 0x00, 0x38, 0xea,
1539 0xdf, 0xa2, 0x51, 0xb2,
1540 0x62, 0x60, 0x62, 0x60,
1541 0x4e, 0x4a, 0x2c, 0x62,
1542 0x60, 0x4e, 0xcb, 0xcf,
1543 0x87, 0x12, 0x40, 0x2e,
1544 0x00, 0x00, 0x00, 0xff,
1545 0xff
1546 };
1547 const unsigned char kV3FrameData[] = {
1548 0x80, kVer, 0x00, 0x01,
1549 0x00, 0x00, 0x00, 0x27,
1550 0x00, 0x00, 0x00, 0x01,
1551 0x00, 0x00, 0x00, 0x00,
1552 0x80, 0x00, 0x38, 0xEA,
1553 0xE3, 0xC6, 0xA7, 0xC2,
1554 0x02, 0xE5, 0x0E, 0x50,
1555 0xC2, 0x4B, 0x4A, 0x04,
1556 0xE5, 0x0B, 0xE6, 0xB4,
1557 0xFC, 0x7C, 0x24, 0x0A,
1558 0x28, 0x08, 0x00, 0x00,
1559 0x00, 0xFF, 0xFF
1560 };
1561 scoped_ptr<SpdyFrame> frame(framer.CreateSynStream(
1562 1, 0, priority, CONTROL_FLAG_NONE, true, &headers));
1563 CompareFrame(kDescription,
1564 *frame,
1565 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
1566 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
1567 : arraysize(kV3FrameData));
1568 }
1569 }
1570
1571 TEST_F(SpdyFramerSpdy3Test, CreateSynReplyUncompressed) {
1572 SpdyFramer framer(kVer);
1573 framer.set_enable_compression(false);
1574
1575 {
1576 const char kDescription[] = "SYN_REPLY frame, no FIN";
1577
1578 SpdyHeaderBlock headers;
1579 headers["bar"] = "foo";
1580 headers["foo"] = "bar";
1581
1582 const unsigned char kV2FrameData[] = {
1583 0x80, kVer, 0x00, 0x02,
1584 0x00, 0x00, 0x00, 0x1C,
1585 0x00, 0x00, 0x00, 0x01,
1586 0x00, 0x00, 0x00, 0x02,
1587 0x00, 0x03, 'b', 'a',
1588 'r', 0x00, 0x03, 'f',
1589 'o', 'o', 0x00, 0x03,
1590 'f', 'o', 'o', 0x00,
1591 0x03, 'b', 'a', 'r'
1592 };
1593 const unsigned char kV3FrameData[] = {
1594 0x80, kVer, 0x00, 0x02,
1595 0x00, 0x00, 0x00, 0x24,
1596 0x00, 0x00, 0x00, 0x01,
1597 0x00, 0x00, 0x00, 0x02,
1598 0x00, 0x00, 0x00, 0x03,
1599 'b', 'a', 'r', 0x00,
1600 0x00, 0x00, 0x03, 'f',
1601 'o', 'o', 0x00, 0x00,
1602 0x00, 0x03, 'f', 'o',
1603 'o', 0x00, 0x00, 0x00,
1604 0x03, 'b', 'a', 'r'
1605 };
1606 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
1607 1, CONTROL_FLAG_NONE, false, &headers));
1608 CompareFrame(kDescription,
1609 *frame,
1610 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
1611 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
1612 : arraysize(kV3FrameData));
1613 }
1614
1615 {
1616 const char kDescription[] =
1617 "SYN_REPLY frame with a 0-length header name, FIN, max stream ID";
1618
1619 SpdyHeaderBlock headers;
1620 headers[""] = "foo";
1621 headers["foo"] = "bar";
1622
1623 const unsigned char kV2FrameData[] = {
1624 0x80, kVer, 0x00, 0x02,
1625 0x01, 0x00, 0x00, 0x19,
1626 0x7f, 0xff, 0xff, 0xff,
1627 0x00, 0x00, 0x00, 0x02,
1628 0x00, 0x00, 0x00, 0x03,
1629 'f', 'o', 'o', 0x00,
1630 0x03, 'f', 'o', 'o',
1631 0x00, 0x03, 'b', 'a',
1632 'r'
1633 };
1634 const unsigned char kV3FrameData[] = {
1635 0x80, kVer, 0x00, 0x02,
1636 0x01, 0x00, 0x00, 0x21,
1637 0x7f, 0xff, 0xff, 0xff,
1638 0x00, 0x00, 0x00, 0x02,
1639 0x00, 0x00, 0x00, 0x00,
1640 0x00, 0x00, 0x00, 0x03,
1641 'f', 'o', 'o', 0x00,
1642 0x00, 0x00, 0x03, 'f',
1643 'o', 'o', 0x00, 0x00,
1644 0x00, 0x03, 'b', 'a',
1645 'r'
1646 };
1647 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
1648 0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
1649 CompareFrame(kDescription,
1650 *frame,
1651 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
1652 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
1653 : arraysize(kV3FrameData));
1654 }
1655
1656 {
1657 const char kDescription[] =
1658 "SYN_REPLY frame with a 0-length header val, FIN, max stream ID";
1659
1660 SpdyHeaderBlock headers;
1661 headers["bar"] = "foo";
1662 headers["foo"] = "";
1663
1664 const unsigned char kV2FrameData[] = {
1665 0x80, kVer, 0x00, 0x02,
1666 0x01, 0x00, 0x00, 0x19,
1667 0x7f, 0xff, 0xff, 0xff,
1668 0x00, 0x00, 0x00, 0x02,
1669 0x00, 0x03, 'b', 'a',
1670 'r', 0x00, 0x03, 'f',
1671 'o', 'o', 0x00, 0x03,
1672 'f', 'o', 'o', 0x00,
1673 0x00
1674 };
1675 const unsigned char kV3FrameData[] = {
1676 0x80, kVer, 0x00, 0x02,
1677 0x01, 0x00, 0x00, 0x21,
1678 0x7f, 0xff, 0xff, 0xff,
1679 0x00, 0x00, 0x00, 0x02,
1680 0x00, 0x00, 0x00, 0x03,
1681 'b', 'a', 'r', 0x00,
1682 0x00, 0x00, 0x03, 'f',
1683 'o', 'o', 0x00, 0x00,
1684 0x00, 0x03, 'f', 'o',
1685 'o', 0x00, 0x00, 0x00,
1686 0x00
1687 };
1688 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
1689 0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
1690 CompareFrame(kDescription,
1691 *frame,
1692 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
1693 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
1694 : arraysize(kV3FrameData));
1695 }
1696 }
1697
1698 TEST_F(SpdyFramerSpdy3Test, CreateSynReplyCompressed) {
1699 SpdyFramer framer(kVer);
1700 framer.set_enable_compression(true);
1701
1702 {
1703 const char kDescription[] = "SYN_REPLY frame, no FIN";
1704
1705 SpdyHeaderBlock headers;
1706 headers["bar"] = "foo";
1707 headers["foo"] = "bar";
1708
1709 const unsigned char kV2FrameData[] = {
1710 0x80, kVer, 0x00, 0x02,
1711 0x00, 0x00, 0x00, 0x21,
1712 0x00, 0x00, 0x00, 0x01,
1713 0x00, 0x00, 0x38, 0xea,
1714 0xdf, 0xa2, 0x51, 0xb2,
1715 0x62, 0x60, 0x62, 0x60,
1716 0x4e, 0x4a, 0x2c, 0x62,
1717 0x60, 0x4e, 0xcb, 0xcf,
1718 0x87, 0x12, 0x40, 0x2e,
1719 0x00, 0x00, 0x00, 0xff,
1720 0xff
1721 };
1722 const unsigned char kV3FrameData[] = {
1723 0x80, kVer, 0x00, 0x02,
1724 0x00, 0x00, 0x00, 0x21,
1725 0x00, 0x00, 0x00, 0x01,
1726 0x38, 0xea, 0xe3, 0xc6,
1727 0xa7, 0xc2, 0x02, 0xe5,
1728 0x0e, 0x50, 0xc2, 0x4b,
1729 0x4a, 0x04, 0xe5, 0x0b,
1730 0xe6, 0xb4, 0xfc, 0x7c,
1731 0x24, 0x0a, 0x28, 0x08,
1732 0x00, 0x00, 0x00, 0xff,
1733 0xff
1734 };
1735 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
1736 1, CONTROL_FLAG_NONE, true, &headers));
1737 CompareFrame(kDescription,
1738 *frame,
1739 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
1740 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
1741 : arraysize(kV3FrameData));
1742 }
1743 }
1744
1745 TEST_F(SpdyFramerSpdy3Test, CreateRstStream) {
1746 SpdyFramer framer(kVer);
1747
1748 {
1749 const char kDescription[] = "RST_STREAM frame";
1750 const unsigned char kFrameData[] = {
1751 0x80, kVer, 0x00, 0x03,
1752 0x00, 0x00, 0x00, 0x08,
1753 0x00, 0x00, 0x00, 0x01,
1754 0x00, 0x00, 0x00, 0x01,
1755 };
1756 scoped_ptr<SpdyRstStreamControlFrame> frame(
1757 framer.CreateRstStream(1, PROTOCOL_ERROR));
1758 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1759 EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get()));
1760 }
1761
1762 {
1763 const char kDescription[] = "RST_STREAM frame with max stream ID";
1764 const unsigned char kFrameData[] = {
1765 0x80, kVer, 0x00, 0x03,
1766 0x00, 0x00, 0x00, 0x08,
1767 0x7f, 0xff, 0xff, 0xff,
1768 0x00, 0x00, 0x00, 0x01,
1769 };
1770 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF,
1771 PROTOCOL_ERROR));
1772 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1773 }
1774
1775 {
1776 const char kDescription[] = "RST_STREAM frame with max status code";
1777 const unsigned char kFrameData[] = {
1778 0x80, kVer, 0x00, 0x03,
1779 0x00, 0x00, 0x00, 0x08,
1780 0x7f, 0xff, 0xff, 0xff,
1781 0x00, 0x00, 0x00, 0x06,
1782 };
1783 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF,
1784 INTERNAL_ERROR));
1785 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1786 }
1787 }
1788
1789 TEST_F(SpdyFramerSpdy3Test, CreateSettings) {
1790 SpdyFramer framer(kVer);
1791
1792 {
1793 const char kDescription[] = "Network byte order SETTINGS frame";
1794
1795 uint32 kValue = 0x0a0b0c0d;
1796 uint8 kFlags = 0x04;
1797 uint32 kId = 0x030201;
1798 SettingsFlagsAndId idAndFlags(kFlags, kId);
1799
1800 SpdySettings settings;
1801 settings.push_back(SpdySetting(idAndFlags, kValue));
1802
1803 EXPECT_EQ(kValue, settings.back().second);
1804 EXPECT_EQ(kFlags, settings.back().first.flags());
1805 EXPECT_EQ(kId, settings.back().first.id());
1806
1807 const unsigned char kFrameDatav2[] = {
1808 0x80, kVer, 0x00, 0x04,
1809 0x00, 0x00, 0x00, 0x0c,
1810 0x00, 0x00, 0x00, 0x01,
1811 0x01, 0x02, 0x03, 0x04,
1812 0x0a, 0x0b, 0x0c, 0x0d,
1813 };
1814
1815 const unsigned char kFrameDatav3[] = {
1816 0x80, kVer, 0x00, 0x04,
1817 0x00, 0x00, 0x00, 0x0c,
1818 0x00, 0x00, 0x00, 0x01,
1819 0x04, 0x03, 0x02, 0x01,
1820 0x0a, 0x0b, 0x0c, 0x0d,
1821 };
1822
1823 scoped_ptr<SpdySettingsControlFrame> frame(framer.CreateSettings(settings));
1824 CompareFrame(kDescription,
1825 *frame,
1826 (SPDY_VERSION_FOR_TESTS < 3) ? kFrameDatav2 : kFrameDatav3,
1827 arraysize(kFrameDatav3)); // Size is unchanged among versions.
1828 EXPECT_EQ(SpdyFramer::kInvalidStream,
1829 SpdyFramer::GetControlFrameStreamId(frame.get()));
1830
1831 // Make sure that ParseSettings also works as advertised.
1832 SpdySettings parsed_settings;
1833 EXPECT_TRUE(framer.ParseSettings(frame.get(), &parsed_settings));
1834 EXPECT_EQ(settings.size(), parsed_settings.size());
1835 EXPECT_EQ(kFlags, parsed_settings.back().first.flags());
1836 EXPECT_EQ(kId, parsed_settings.back().first.id());
1837 }
1838
1839 {
1840 const char kDescription[] = "Basic SETTINGS frame";
1841
1842 SpdySettings settings;
1843 settings.push_back(
1844 SpdySettingFromWireFormat(0x00000000, 0x00000000)); // 1st Setting
1845 settings.push_back(
1846 SpdySettingFromWireFormat(0xffffffff, 0x00000001)); // 2nd Setting
1847 settings.push_back(
1848 SpdySettingFromWireFormat(0xff000001, 0x00000002)); // 3rd Setting
1849
1850 // Duplicates allowed
1851 settings.push_back(
1852 SpdySettingFromWireFormat(0x01000002, 0x00000003)); // 4th Setting
1853 settings.push_back(
1854 SpdySettingFromWireFormat(0x01000002, 0x00000003)); // 5th Setting
1855
1856 settings.push_back(
1857 SpdySettingFromWireFormat(0x01000003, 0x000000ff)); // 6th Setting
1858 settings.push_back(
1859 SpdySettingFromWireFormat(0x01000004, 0xff000001)); // 7th Setting
1860 settings.push_back(
1861 SpdySettingFromWireFormat(0x01000004, 0xffffffff)); // 8th Setting
1862
1863 const unsigned char kFrameData[] = {
1864 0x80, kVer, 0x00, 0x04,
1865 0x00, 0x00, 0x00, 0x44,
1866 0x00, 0x00, 0x00, 0x08,
1867 0x00, 0x00, 0x00, 0x00, // 1st Setting
1868 0x00, 0x00, 0x00, 0x00,
1869 0xff, 0xff, 0xff, 0xff, // 2nd Setting
1870 0x00, 0x00, 0x00, 0x01,
1871 0x01, 0x00, 0x00, 0xff, // 3rd Setting
1872 0x00, 0x00, 0x00, 0x02,
1873 0x02, 0x00, 0x00, 0x01, // 4th Setting
1874 0x00, 0x00, 0x00, 0x03,
1875 0x02, 0x00, 0x00, 0x01, // 5th Setting
1876 0x00, 0x00, 0x00, 0x03,
1877 0x03, 0x00, 0x00, 0x01, // 6th Setting
1878 0x00, 0x00, 0x00, 0xff,
1879 0x04, 0x00, 0x00, 0x01, // 7th Setting
1880 0xff, 0x00, 0x00, 0x01,
1881 0x04, 0x00, 0x00, 0x01, // 8th Setting
1882 0xff, 0xff, 0xff, 0xff,
1883 };
1884 scoped_ptr<SpdySettingsControlFrame> frame(framer.CreateSettings(settings));
1885 CompareFrame(kDescription,
1886 *frame,
1887 kFrameData,
1888 arraysize(kFrameData));
1889 EXPECT_EQ(SpdyFramer::kInvalidStream,
1890 SpdyFramer::GetControlFrameStreamId(frame.get()));
1891 }
1892
1893 {
1894 const char kDescription[] = "Empty SETTINGS frame";
1895
1896 SpdySettings settings;
1897
1898 const unsigned char kFrameData[] = {
1899 0x80, kVer, 0x00, 0x04,
1900 0x00, 0x00, 0x00, 0x04,
1901 0x00, 0x00, 0x00, 0x00,
1902 };
1903 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
1904 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1905 }
1906 }
1907
1908 TEST_F(SpdyFramerSpdy3Test, CreatePingFrame) {
1909 SpdyFramer framer(kVer);
1910
1911 {
1912 const char kDescription[] = "PING frame";
1913 const unsigned char kFrameData[] = {
1914 0x80, kVer, 0x00, 0x06,
1915 0x00, 0x00, 0x00, 0x04,
1916 0x12, 0x34, 0x56, 0x78,
1917 };
1918 scoped_ptr<SpdyPingControlFrame> frame(framer.CreatePingFrame(0x12345678u));
1919 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1920 EXPECT_EQ(SpdyFramer::kInvalidStream,
1921 SpdyFramer::GetControlFrameStreamId(frame.get()));
1922 }
1923 }
1924
1925 TEST_F(SpdyFramerSpdy3Test, CreateGoAway) {
1926 SpdyFramer framer(kVer);
1927
1928 {
1929 const char kDescription[] = "GOAWAY frame";
1930 const unsigned char kFrameData[] = {
1931 0x80, kVer, 0x00, 0x07,
1932 0x00, 0x00, 0x00, 0x04,
1933 0x00, 0x00, 0x00, 0x00,
1934 };
1935 scoped_ptr<SpdyGoAwayControlFrame> frame(framer.CreateGoAway(0));
1936 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1937 EXPECT_EQ(SpdyFramer::kInvalidStream,
1938 SpdyFramer::GetControlFrameStreamId(frame.get()));
1939 }
1940
1941 {
1942 const char kDescription[] = "GOAWAY frame with max stream ID";
1943 const unsigned char kFrameData[] = {
1944 0x80, kVer, 0x00, 0x07,
1945 0x00, 0x00, 0x00, 0x04,
1946 0x7f, 0xff, 0xff, 0xff,
1947 };
1948 scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF));
1949 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1950 }
1951 }
1952
1953 TEST_F(SpdyFramerSpdy3Test, CreateHeadersUncompressed) {
1954 SpdyFramer framer(kVer);
1955 framer.set_enable_compression(false);
1956
1957 {
1958 const char kDescription[] = "HEADERS frame, no FIN";
1959
1960 SpdyHeaderBlock headers;
1961 headers["bar"] = "foo";
1962 headers["foo"] = "bar";
1963
1964 const unsigned char kV2FrameData[] = {
1965 0x80, kVer, 0x00, 0x08,
1966 0x00, 0x00, 0x00, 0x1C,
1967 0x00, 0x00, 0x00, 0x01,
1968 0x00, 0x00, 0x00, 0x02,
1969 0x00, 0x03, 'b', 'a',
1970 'r', 0x00, 0x03, 'f',
1971 'o', 'o', 0x00, 0x03,
1972 'f', 'o', 'o', 0x00,
1973 0x03, 'b', 'a', 'r'
1974 };
1975 const unsigned char kV3FrameData[] = {
1976 0x80, kVer, 0x00, 0x08,
1977 0x00, 0x00, 0x00, 0x24,
1978 0x00, 0x00, 0x00, 0x01,
1979 0x00, 0x00, 0x00, 0x02,
1980 0x00, 0x00, 0x00, 0x03,
1981 'b', 'a', 'r', 0x00,
1982 0x00, 0x00, 0x03, 'f',
1983 'o', 'o', 0x00, 0x00,
1984 0x00, 0x03, 'f', 'o',
1985 'o', 0x00, 0x00, 0x00,
1986 0x03, 'b', 'a', 'r'
1987 };
1988 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
1989 1, CONTROL_FLAG_NONE, false, &headers));
1990 CompareFrame(kDescription,
1991 *frame,
1992 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
1993 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
1994 : arraysize(kV3FrameData));
1995 }
1996
1997 {
1998 const char kDescription[] =
1999 "HEADERS frame with a 0-length header name, FIN, max stream ID";
2000
2001 SpdyHeaderBlock headers;
2002 headers[""] = "foo";
2003 headers["foo"] = "bar";
2004
2005 const unsigned char kV2FrameData[] = {
2006 0x80, kVer, 0x00, 0x08,
2007 0x01, 0x00, 0x00, 0x19,
2008 0x7f, 0xff, 0xff, 0xff,
2009 0x00, 0x00, 0x00, 0x02,
2010 0x00, 0x00, 0x00, 0x03,
2011 'f', 'o', 'o', 0x00,
2012 0x03, 'f', 'o', 'o',
2013 0x00, 0x03, 'b', 'a',
2014 'r'
2015 };
2016 const unsigned char kV3FrameData[] = {
2017 0x80, kVer, 0x00, 0x08,
2018 0x01, 0x00, 0x00, 0x21,
2019 0x7f, 0xff, 0xff, 0xff,
2020 0x00, 0x00, 0x00, 0x02,
2021 0x00, 0x00, 0x00, 0x00,
2022 0x00, 0x00, 0x00, 0x03,
2023 'f', 'o', 'o', 0x00,
2024 0x00, 0x00, 0x03, 'f',
2025 'o', 'o', 0x00, 0x00,
2026 0x00, 0x03, 'b', 'a',
2027 'r'
2028 };
2029 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
2030 0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
2031 CompareFrame(kDescription,
2032 *frame,
2033 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
2034 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
2035 : arraysize(kV3FrameData));
2036 }
2037
2038 {
2039 const char kDescription[] =
2040 "HEADERS frame with a 0-length header val, FIN, max stream ID";
2041
2042 SpdyHeaderBlock headers;
2043 headers["bar"] = "foo";
2044 headers["foo"] = "";
2045
2046 const unsigned char kV2FrameData[] = {
2047 0x80, kVer, 0x00, 0x08,
2048 0x01, 0x00, 0x00, 0x19,
2049 0x7f, 0xff, 0xff, 0xff,
2050 0x00, 0x00, 0x00, 0x02,
2051 0x00, 0x03, 'b', 'a',
2052 'r', 0x00, 0x03, 'f',
2053 'o', 'o', 0x00, 0x03,
2054 'f', 'o', 'o', 0x00,
2055 0x00
2056 };
2057 const unsigned char kV3FrameData[] = {
2058 0x80, kVer, 0x00, 0x08,
2059 0x01, 0x00, 0x00, 0x21,
2060 0x7f, 0xff, 0xff, 0xff,
2061 0x00, 0x00, 0x00, 0x02,
2062 0x00, 0x00, 0x00, 0x03,
2063 'b', 'a', 'r', 0x00,
2064 0x00, 0x00, 0x03, 'f',
2065 'o', 'o', 0x00, 0x00,
2066 0x00, 0x03, 'f', 'o',
2067 'o', 0x00, 0x00, 0x00,
2068 0x00
2069 };
2070 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
2071 0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
2072 CompareFrame(kDescription,
2073 *frame,
2074 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
2075 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
2076 : arraysize(kV3FrameData));
2077 }
2078 }
2079
2080 TEST_F(SpdyFramerSpdy3Test, CreateHeadersCompressed) {
2081 SpdyFramer framer(kVer);
2082 framer.set_enable_compression(true);
2083
2084 {
2085 const char kDescription[] = "HEADERS frame, no FIN";
2086
2087 SpdyHeaderBlock headers;
2088 headers["bar"] = "foo";
2089 headers["foo"] = "bar";
2090
2091 const unsigned char kV2FrameData[] = {
2092 0x80, kVer, 0x00, 0x08,
2093 0x00, 0x00, 0x00, 0x21,
2094 0x00, 0x00, 0x00, 0x01,
2095 0x00, 0x00, 0x38, 0xea,
2096 0xdf, 0xa2, 0x51, 0xb2,
2097 0x62, 0x60, 0x62, 0x60,
2098 0x4e, 0x4a, 0x2c, 0x62,
2099 0x60, 0x4e, 0xcb, 0xcf,
2100 0x87, 0x12, 0x40, 0x2e,
2101 0x00, 0x00, 0x00, 0xff,
2102 0xff
2103 };
2104 const unsigned char kV3FrameData[] = {
2105 0x80, kVer, 0x00, 0x08,
2106 0x00, 0x00, 0x00, 0x21,
2107 0x00, 0x00, 0x00, 0x01,
2108 0x38, 0xea, 0xe3, 0xc6,
2109 0xa7, 0xc2, 0x02, 0xe5,
2110 0x0e, 0x50, 0xc2, 0x4b,
2111 0x4a, 0x04, 0xe5, 0x0b,
2112 0xe6, 0xb4, 0xfc, 0x7c,
2113 0x24, 0x0a, 0x28, 0x08,
2114 0x00, 0x00, 0x00, 0xff,
2115 0xff
2116 };
2117 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
2118 1, CONTROL_FLAG_NONE, true, &headers));
2119 CompareFrame(kDescription,
2120 *frame,
2121 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData,
2122 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData)
2123 : arraysize(kV3FrameData));
2124 }
2125 }
2126
2127 TEST_F(SpdyFramerSpdy3Test, CreateWindowUpdate) {
2128 SpdyFramer framer(kVer);
2129
2130 {
2131 const char kDescription[] = "WINDOW_UPDATE frame";
2132 const unsigned char kFrameData[] = {
2133 0x80, kVer, 0x00, 0x09,
2134 0x00, 0x00, 0x00, 0x08,
2135 0x00, 0x00, 0x00, 0x01,
2136 0x00, 0x00, 0x00, 0x01,
2137 };
2138 scoped_ptr<SpdyWindowUpdateControlFrame> frame(
2139 framer.CreateWindowUpdate(1, 1));
2140 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
2141 EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get()));
2142 }
2143
2144 {
2145 const char kDescription[] = "WINDOW_UPDATE frame with max stream ID";
2146 const unsigned char kFrameData[] = {
2147 0x80, kVer, 0x00, 0x09,
2148 0x00, 0x00, 0x00, 0x08,
2149 0x7f, 0xff, 0xff, 0xff,
2150 0x00, 0x00, 0x00, 0x01,
2151 };
2152 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(0x7FFFFFFF, 1));
2153 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
2154 }
2155
2156 {
2157 const char kDescription[] = "WINDOW_UPDATE frame with max window delta";
2158 const unsigned char kFrameData[] = {
2159 0x80, kVer, 0x00, 0x09,
2160 0x00, 0x00, 0x00, 0x08,
2161 0x00, 0x00, 0x00, 0x01,
2162 0x7f, 0xff, 0xff, 0xff,
2163 };
2164 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x7FFFFFFF));
2165 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
2166 }
2167 }
2168
2169 TEST_F(SpdyFramerSpdy3Test, DuplicateFrame) {
2170 SpdyFramer framer(kVer);
2171
2172 {
2173 const char kDescription[] = "PING frame";
2174 const unsigned char kFrameData[] = {
2175 0x80, kVer, 0x00, 0x06,
2176 0x00, 0x00, 0x00, 0x04,
2177 0x12, 0x34, 0x56, 0x78,
2178 };
2179 scoped_ptr<SpdyFrame> frame1(framer.CreatePingFrame(0x12345678u));
2180 CompareFrame(kDescription, *frame1, kFrameData, arraysize(kFrameData));
2181
2182 scoped_ptr<SpdyFrame> frame2(framer.DuplicateFrame(*frame1));
2183 CompareFrame(kDescription, *frame2, kFrameData, arraysize(kFrameData));
2184 }
2185 }
2186
2187 // This test case reproduces conditions that caused ExpandControlFrameBuffer to
2188 // fail to expand the buffer control frame buffer when it should have, allowing
2189 // the framer to overrun the buffer, and smash other heap contents. This test
2190 // relies on the debug version of the heap manager, which checks for buffer
2191 // overrun errors during delete processing. Regression test for b/2974814.
2192 TEST_F(SpdyFramerSpdy3Test, ExpandBuffer_HeapSmash) {
2193 // Sweep through the area of problematic values, to make sure we always cover
2194 // the danger zone, even if it moves around at bit due to SPDY changes.
2195 for (uint16 val2_len = SpdyFramer::kControlFrameBufferInitialSize - 50;
2196 val2_len < SpdyFramer::kControlFrameBufferInitialSize;
2197 val2_len++) {
2198 std::string val2 = std::string(val2_len, 'a');
2199 SpdyHeaderBlock headers;
2200 headers["bar"] = "foo";
2201 headers["foo"] = "baz";
2202 headers["grue"] = val2.c_str();
2203 SpdyFramer framer(kVer);
2204 scoped_ptr<SpdySynStreamControlFrame> template_frame(
2205 framer.CreateSynStream(1, // stream_id
2206 0, // associated_stream_id
2207 1, // priority
2208 CONTROL_FLAG_NONE,
2209 false, // compress
2210 &headers));
2211 EXPECT_TRUE(template_frame.get() != NULL);
2212 TestSpdyVisitor visitor;
2213 visitor.SimulateInFramer(
2214 reinterpret_cast<unsigned char*>(template_frame.get()->data()),
2215 template_frame.get()->length() + SpdyControlFrame::kHeaderSize);
2216 EXPECT_EQ(1, visitor.syn_frame_count_);
2217 }
2218 }
2219
2220 TEST_F(SpdyFramerSpdy3Test, ControlFrameSizesAreValidated) {
2221 // Create a GoAway frame that has a few extra bytes at the end.
2222 // We create enough overhead to require the framer to expand its frame buffer.
2223 size_t overhead = SpdyFramer::kUncompressedControlFrameBufferInitialSize;
2224 SpdyFramer framer(kVer);
2225 scoped_ptr<SpdyGoAwayControlFrame> goaway(framer.CreateGoAway(1));
2226 goaway->set_length(goaway->length() + overhead);
2227 std::string pad('A', overhead);
2228 TestSpdyVisitor visitor;
2229
2230 // First attempt without validation on.
2231 visitor.framer_.set_validate_control_frame_sizes(false);
2232 visitor.SimulateInFramer(
2233 reinterpret_cast<unsigned char*>(goaway->data()),
2234 goaway->length() - overhead + SpdyControlFrame::kHeaderSize);
2235 visitor.SimulateInFramer(
2236 reinterpret_cast<const unsigned char*>(pad.c_str()),
2237 overhead);
2238 EXPECT_EQ(0, visitor.error_count_); // Not an error.
2239 EXPECT_EQ(1, visitor.goaway_count_); // The goaway was parsed.
2240
2241 // Attempt with validation on.
2242 visitor.framer_.set_validate_control_frame_sizes(true);
2243 visitor.SimulateInFramer(
2244 reinterpret_cast<unsigned char*>(goaway->data()),
2245 goaway->length() - overhead + SpdyControlFrame::kHeaderSize);
2246 visitor.SimulateInFramer(
2247 reinterpret_cast<const unsigned char*>(pad.c_str()),
2248 overhead);
2249 EXPECT_EQ(1, visitor.error_count_); // This generated an error.
2250 EXPECT_EQ(1, visitor.goaway_count_); // Unchanged from before.
2251 }
2252
2253 TEST_F(SpdyFramerSpdy3Test, ReadZeroLenSettingsFrame) {
2254 SpdyFramer framer(kVer);
2255 SpdySettings settings;
2256 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
2257 control_frame->set_length(0);
2258 TestSpdyVisitor visitor;
2259 visitor.use_compression_ = false;
2260 visitor.SimulateInFramer(
2261 reinterpret_cast<unsigned char*>(control_frame->data()),
2262 control_frame.get()->length() + SpdyControlFrame::kHeaderSize);
2263 // Should generate an error, since zero-len settings frames are unsupported.
2264 EXPECT_EQ(1, visitor.error_count_);
2265 }
2266
2267 // Tests handling of SETTINGS frames with invalid length.
2268 TEST_F(SpdyFramerSpdy3Test, ReadBogusLenSettingsFrame) {
2269 SpdyFramer framer(kVer);
2270 SpdySettings settings;
2271 // Add a setting to pad the frame so that we don't get a buffer overflow when
2272 // calling SimulateInFramer() below.
2273 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002));
2274 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
2275 control_frame->set_length(5);
2276 TestSpdyVisitor visitor;
2277 visitor.use_compression_ = false;
2278 visitor.SimulateInFramer(
2279 reinterpret_cast<unsigned char*>(control_frame->data()),
2280 control_frame.get()->length() + SpdyControlFrame::kHeaderSize);
2281 // Should generate an error, since zero-len settings frames are unsupported.
2282 EXPECT_EQ(1, visitor.error_count_);
2283 }
2284
2285 // Tests handling of SETTINGS frames larger than the frame buffer size.
2286 TEST_F(SpdyFramerSpdy3Test, ReadLargeSettingsFrame) {
2287 SpdyFramer framer(kVer);
2288 SpdySettings settings;
2289 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002));
2290 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 2), 0x00000003));
2291 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000004));
2292 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
2293 EXPECT_LT(SpdyFramer::kUncompressedControlFrameBufferInitialSize,
2294 control_frame->length() + SpdyControlFrame::kHeaderSize);
2295 TestSpdyVisitor visitor;
2296 visitor.use_compression_ = false;
2297
2298 // Read all at once.
2299 visitor.SimulateInFramer(
2300 reinterpret_cast<unsigned char*>(control_frame->data()),
2301 control_frame->length() + SpdyControlFrame::kHeaderSize);
2302 EXPECT_EQ(0, visitor.error_count_);
2303 EXPECT_EQ(settings.size(), static_cast<unsigned>(visitor.setting_count_));
2304 EXPECT_EQ(1, visitor.settings_frame_count_);
2305
2306 // Read data in small chunks.
2307 size_t framed_data = 0;
2308 size_t unframed_data = control_frame->length() +
2309 SpdyControlFrame::kHeaderSize;
2310 size_t kReadChunkSize = 5; // Read five bytes at a time.
2311 while (unframed_data > 0) {
2312 size_t to_read = std::min(kReadChunkSize, unframed_data);
2313 visitor.SimulateInFramer(
2314 reinterpret_cast<unsigned char*>(control_frame->data() + framed_data),
2315 to_read);
2316 unframed_data -= to_read;
2317 framed_data += to_read;
2318 }
2319 EXPECT_EQ(0, visitor.error_count_);
2320 EXPECT_EQ(settings.size() * 2, static_cast<unsigned>(visitor.setting_count_));
2321 EXPECT_EQ(2, visitor.settings_frame_count_);
2322 }
2323
2324 // Tests handling of SETTINGS frame with duplicate entries.
2325 TEST_F(SpdyFramerSpdy3Test, ReadDuplicateSettings) {
2326 SpdyFramer framer(kVer);
2327 SpdySettings settings;
2328 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002));
2329 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000003));
2330 // This last setting should not be processed due to error above.
2331 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000003));
2332 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
2333 TestSpdyVisitor visitor;
2334 visitor.use_compression_ = false;
2335
2336 visitor.SimulateInFramer(
2337 reinterpret_cast<unsigned char*>(control_frame->data()),
2338 control_frame->length() + SpdyControlFrame::kHeaderSize);
2339 EXPECT_EQ(1, visitor.error_count_);
2340 EXPECT_EQ(1, visitor.setting_count_);
2341 EXPECT_EQ(1, visitor.settings_frame_count_);
2342 }
2343
2344 // Tests handling of SETTINGS frame with entries out of order.
2345 TEST_F(SpdyFramerSpdy3Test, ReadOutOfOrderSettings) {
2346 SpdyFramer framer(kVer);
2347 SpdySettings settings;
2348 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 2), 0x00000002));
2349 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000003));
2350 // This last setting should not be processed due to error above.
2351 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000003));
2352 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
2353 TestSpdyVisitor visitor;
2354 visitor.use_compression_ = false;
2355
2356 visitor.SimulateInFramer(
2357 reinterpret_cast<unsigned char*>(control_frame->data()),
2358 control_frame->length() + SpdyControlFrame::kHeaderSize);
2359 EXPECT_EQ(1, visitor.error_count_);
2360 EXPECT_EQ(1, visitor.setting_count_);
2361 EXPECT_EQ(1, visitor.settings_frame_count_);
2362 }
2363
2364 TEST_F(SpdyFramerSpdy3Test, ReadCredentialFrame) {
2365 SpdyCredential credential;
2366 credential.slot = 3;
2367 credential.proof = "proof";
2368 credential.certs.push_back("a cert");
2369 credential.certs.push_back("another cert");
2370 credential.certs.push_back("final cert");
2371 SpdyFramer framer(kVer);
2372 scoped_ptr<SpdyFrame> control_frame(
2373 framer.CreateCredentialFrame(credential));
2374 EXPECT_TRUE(control_frame.get() != NULL);
2375 TestSpdyVisitor visitor;
2376 visitor.use_compression_ = false;
2377 visitor.SimulateInFramer(
2378 reinterpret_cast<unsigned char*>(control_frame.get()->data()),
2379 control_frame.get()->length() + SpdyControlFrame::kHeaderSize);
2380 EXPECT_EQ(0, visitor.error_count_);
2381 EXPECT_EQ(1, visitor.credential_count_);
2382 EXPECT_EQ(control_frame->length(), visitor.credential_buffer_length_);
2383 EXPECT_EQ(credential.slot, visitor.credential_.slot);
2384 EXPECT_EQ(credential.proof, visitor.credential_.proof);
2385 EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size());
2386 for (size_t i = 0; i < credential.certs.size(); i++) {
2387 EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]);
2388 }
2389 }
2390
2391 TEST_F(SpdyFramerSpdy3Test, ReadCredentialFrameWithCorruptProof) {
2392 SpdyCredential credential;
2393 credential.slot = 3;
2394 credential.proof = "proof";
2395 credential.certs.push_back("a cert");
2396 credential.certs.push_back("another cert");
2397 credential.certs.push_back("final cert");
2398 SpdyFramer framer(kVer);
2399 scoped_ptr<SpdyFrame> control_frame(
2400 framer.CreateCredentialFrame(credential));
2401 EXPECT_TRUE(control_frame.get() != NULL);
2402 TestSpdyVisitor visitor;
2403 visitor.use_compression_ = false;
2404 unsigned char* data =
2405 reinterpret_cast<unsigned char*>(control_frame.get()->data());
2406 size_t offset = SpdyControlFrame::kHeaderSize + 4;
2407 data[offset] = 0xFF; // Proof length is past the end of the frame
2408 visitor.SimulateInFramer(
2409 data, control_frame.get()->length() + SpdyControlFrame::kHeaderSize);
2410 EXPECT_EQ(1, visitor.error_count_);
2411 }
2412
2413 TEST_F(SpdyFramerSpdy3Test, ReadCredentialFrameWithCorruptCertificate) {
2414 SpdyCredential credential;
2415 credential.slot = 3;
2416 credential.proof = "proof";
2417 credential.certs.push_back("a cert");
2418 credential.certs.push_back("another cert");
2419 credential.certs.push_back("final cert");
2420 SpdyFramer framer(kVer);
2421 scoped_ptr<SpdyFrame> control_frame(
2422 framer.CreateCredentialFrame(credential));
2423 EXPECT_TRUE(control_frame.get() != NULL);
2424 TestSpdyVisitor visitor;
2425 visitor.use_compression_ = false;
2426 unsigned char* data =
2427 reinterpret_cast<unsigned char*>(control_frame.get()->data());
2428 size_t offset = SpdyControlFrame::kHeaderSize + credential.proof.length();
2429 data[offset] = 0xFF; // Certificate length is past the end of the frame
2430 visitor.SimulateInFramer(
2431 data, control_frame.get()->length() + SpdyControlFrame::kHeaderSize);
2432 EXPECT_EQ(1, visitor.error_count_);
2433 }
2434
2435 TEST_F(SpdyFramerSpdy3Test, ReadGarbage) {
2436 SpdyFramer framer(kVer);
2437 unsigned char garbage_frame[256];
2438 memset(garbage_frame, ~0, sizeof(garbage_frame));
2439 TestSpdyVisitor visitor;
2440 visitor.use_compression_ = false;
2441 visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame));
2442 EXPECT_EQ(1, visitor.error_count_);
2443 }
2444
2445 TEST_F(SpdyFramerSpdy3Test, ReadGarbageWithValidVersion) {
2446 SpdyFramer framer(kVer);
2447 char garbage_frame[256];
2448 memset(garbage_frame, ~0, sizeof(garbage_frame));
2449 SpdyControlFrame control_frame(&garbage_frame[0], false);
2450 control_frame.set_version(SPDY_VERSION_FOR_TESTS);
2451 TestSpdyVisitor visitor;
2452 visitor.use_compression_ = false;
2453 visitor.SimulateInFramer(
2454 reinterpret_cast<unsigned char*>(control_frame.data()),
2455 sizeof(garbage_frame));
2456 EXPECT_EQ(1, visitor.error_count_);
2457 }
2458
2459 TEST_F(SpdyFramerSpdy3Test, StateToStringTest) {
2460 EXPECT_STREQ("ERROR",
2461 SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR));
2462 EXPECT_STREQ("DONE",
2463 SpdyFramer::StateToString(SpdyFramer::SPDY_DONE));
2464 EXPECT_STREQ("AUTO_RESET",
2465 SpdyFramer::StateToString(SpdyFramer::SPDY_AUTO_RESET));
2466 EXPECT_STREQ("RESET",
2467 SpdyFramer::StateToString(SpdyFramer::SPDY_RESET));
2468 EXPECT_STREQ("READING_COMMON_HEADER",
2469 SpdyFramer::StateToString(
2470 SpdyFramer::SPDY_READING_COMMON_HEADER));
2471 EXPECT_STREQ("CONTROL_FRAME_PAYLOAD",
2472 SpdyFramer::StateToString(
2473 SpdyFramer::SPDY_CONTROL_FRAME_PAYLOAD));
2474 EXPECT_STREQ("IGNORE_REMAINING_PAYLOAD",
2475 SpdyFramer::StateToString(
2476 SpdyFramer::SPDY_IGNORE_REMAINING_PAYLOAD));
2477 EXPECT_STREQ("FORWARD_STREAM_FRAME",
2478 SpdyFramer::StateToString(
2479 SpdyFramer::SPDY_FORWARD_STREAM_FRAME));
2480 EXPECT_STREQ("SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK",
2481 SpdyFramer::StateToString(
2482 SpdyFramer::SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK));
2483 EXPECT_STREQ("SPDY_CONTROL_FRAME_HEADER_BLOCK",
2484 SpdyFramer::StateToString(
2485 SpdyFramer::SPDY_CONTROL_FRAME_HEADER_BLOCK));
2486 EXPECT_STREQ("SPDY_CREDENTIAL_FRAME_PAYLOAD",
2487 SpdyFramer::StateToString(
2488 SpdyFramer::SPDY_CREDENTIAL_FRAME_PAYLOAD));
2489 EXPECT_STREQ("SPDY_SETTINGS_FRAME_PAYLOAD",
2490 SpdyFramer::StateToString(
2491 SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD));
2492 EXPECT_STREQ("UNKNOWN_STATE",
2493 SpdyFramer::StateToString(
2494 SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD + 1));
2495 }
2496
2497 TEST_F(SpdyFramerSpdy3Test, ErrorCodeToStringTest) {
2498 EXPECT_STREQ("NO_ERROR",
2499 SpdyFramer::ErrorCodeToString(SpdyFramer::SPDY_NO_ERROR));
2500 EXPECT_STREQ("INVALID_CONTROL_FRAME",
2501 SpdyFramer::ErrorCodeToString(
2502 SpdyFramer::SPDY_INVALID_CONTROL_FRAME));
2503 EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE",
2504 SpdyFramer::ErrorCodeToString(
2505 SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE));
2506 EXPECT_STREQ("ZLIB_INIT_FAILURE",
2507 SpdyFramer::ErrorCodeToString(
2508 SpdyFramer::SPDY_ZLIB_INIT_FAILURE));
2509 EXPECT_STREQ("UNSUPPORTED_VERSION",
2510 SpdyFramer::ErrorCodeToString(
2511 SpdyFramer::SPDY_UNSUPPORTED_VERSION));
2512 EXPECT_STREQ("DECOMPRESS_FAILURE",
2513 SpdyFramer::ErrorCodeToString(
2514 SpdyFramer::SPDY_DECOMPRESS_FAILURE));
2515 EXPECT_STREQ("COMPRESS_FAILURE",
2516 SpdyFramer::ErrorCodeToString(
2517 SpdyFramer::SPDY_COMPRESS_FAILURE));
2518 EXPECT_STREQ("UNKNOWN_ERROR",
2519 SpdyFramer::ErrorCodeToString(SpdyFramer::LAST_ERROR));
2520 }
2521
2522 TEST_F(SpdyFramerSpdy3Test, StatusCodeToStringTest) {
2523 EXPECT_STREQ("INVALID",
2524 SpdyFramer::StatusCodeToString(INVALID));
2525 EXPECT_STREQ("PROTOCOL_ERROR",
2526 SpdyFramer::StatusCodeToString(PROTOCOL_ERROR));
2527 EXPECT_STREQ("INVALID_STREAM",
2528 SpdyFramer::StatusCodeToString(INVALID_STREAM));
2529 EXPECT_STREQ("REFUSED_STREAM",
2530 SpdyFramer::StatusCodeToString(REFUSED_STREAM));
2531 EXPECT_STREQ("UNSUPPORTED_VERSION",
2532 SpdyFramer::StatusCodeToString(UNSUPPORTED_VERSION));
2533 EXPECT_STREQ("CANCEL",
2534 SpdyFramer::StatusCodeToString(CANCEL));
2535 EXPECT_STREQ("INTERNAL_ERROR",
2536 SpdyFramer::StatusCodeToString(INTERNAL_ERROR));
2537 EXPECT_STREQ("FLOW_CONTROL_ERROR",
2538 SpdyFramer::StatusCodeToString(FLOW_CONTROL_ERROR));
2539 EXPECT_STREQ("UNKNOWN_STATUS",
2540 SpdyFramer::StatusCodeToString(NUM_STATUS_CODES));
2541 }
2542
2543 TEST_F(SpdyFramerSpdy3Test, ControlTypeToStringTest) {
2544 EXPECT_STREQ("SYN_STREAM",
2545 SpdyFramer::ControlTypeToString(SYN_STREAM));
2546 EXPECT_STREQ("SYN_REPLY",
2547 SpdyFramer::ControlTypeToString(SYN_REPLY));
2548 EXPECT_STREQ("RST_STREAM",
2549 SpdyFramer::ControlTypeToString(RST_STREAM));
2550 EXPECT_STREQ("SETTINGS",
2551 SpdyFramer::ControlTypeToString(SETTINGS));
2552 EXPECT_STREQ("NOOP",
2553 SpdyFramer::ControlTypeToString(NOOP));
2554 EXPECT_STREQ("PING",
2555 SpdyFramer::ControlTypeToString(PING));
2556 EXPECT_STREQ("GOAWAY",
2557 SpdyFramer::ControlTypeToString(GOAWAY));
2558 EXPECT_STREQ("HEADERS",
2559 SpdyFramer::ControlTypeToString(HEADERS));
2560 EXPECT_STREQ("WINDOW_UPDATE",
2561 SpdyFramer::ControlTypeToString(WINDOW_UPDATE));
2562 EXPECT_STREQ("CREDENTIAL",
2563 SpdyFramer::ControlTypeToString(CREDENTIAL));
2564 EXPECT_STREQ("UNKNOWN_CONTROL_TYPE",
2565 SpdyFramer::ControlTypeToString(NUM_CONTROL_FRAME_TYPES));
2566 }
2567
2568 TEST_F(SpdyFramerSpdy3Test, GetMinimumControlFrameSizeTest) {
2569 EXPECT_EQ(SpdySynStreamControlFrame::size(),
2570 SpdyFramer::GetMinimumControlFrameSize(SYN_STREAM));
2571 EXPECT_EQ(SpdySynReplyControlFrame::size(),
2572 SpdyFramer::GetMinimumControlFrameSize(SYN_REPLY));
2573 EXPECT_EQ(SpdyRstStreamControlFrame::size(),
2574 SpdyFramer::GetMinimumControlFrameSize(RST_STREAM));
2575 EXPECT_EQ(SpdySettingsControlFrame::size(),
2576 SpdyFramer::GetMinimumControlFrameSize(SETTINGS));
2577 EXPECT_EQ(SpdyFrame::kHeaderSize,
2578 SpdyFramer::GetMinimumControlFrameSize(NOOP));
2579 EXPECT_EQ(SpdyPingControlFrame::size(),
2580 SpdyFramer::GetMinimumControlFrameSize(PING));
2581 EXPECT_EQ(SpdyGoAwayControlFrame::size(),
2582 SpdyFramer::GetMinimumControlFrameSize(GOAWAY));
2583 EXPECT_EQ(SpdyHeadersControlFrame::size(),
2584 SpdyFramer::GetMinimumControlFrameSize(HEADERS));
2585 EXPECT_EQ(SpdyWindowUpdateControlFrame::size(),
2586 SpdyFramer::GetMinimumControlFrameSize(WINDOW_UPDATE));
2587 EXPECT_EQ(SpdyCredentialControlFrame::size(),
2588 SpdyFramer::GetMinimumControlFrameSize(CREDENTIAL));
2589 EXPECT_EQ(static_cast<size_t>(0x7FFFFFFF),
2590 SpdyFramer::GetMinimumControlFrameSize(NUM_CONTROL_FRAME_TYPES));
2591 }
2592
2593 TEST_F(SpdyFramerSpdy3Test, CatchProbableHttpResponse) {
2594 SpdyFramerTestUtil::DecompressionVisitor visitor;
2595 visitor.set_allow_data_frames(true);
2596 {
2597 SpdyFramer framer(kVer);
2598 framer.set_visitor(&visitor);
2599 framer.ProcessInput("HTTP/1.1", 8);
2600 EXPECT_TRUE(framer.probable_http_response());
2601 }
2602 {
2603 SpdyFramer framer(kVer);
2604 framer.set_visitor(&visitor);
2605 framer.ProcessInput("HTTP/1.0", 8);
2606 EXPECT_TRUE(framer.probable_http_response());
2607 }
2608 }
2609
2610 TEST_F(SpdyFramerSpdy3Test, SettingsFlagsAndId) {
2611 const uint32 kId = 0x020304;
2612 const uint32 kFlags = 0x01;
2613 const uint32 kWireFormat =
2614 htonl((SPDY_VERSION_FOR_TESTS < 3) ? 0x04030201 : 0x01020304);
2615
2616 SettingsFlagsAndId id_and_flags =
2617 SettingsFlagsAndId::FromWireFormat(SPDY_VERSION_FOR_TESTS, kWireFormat);
2618 EXPECT_EQ(kId, id_and_flags.id());
2619 EXPECT_EQ(kFlags, id_and_flags.flags());
2620 EXPECT_EQ(kWireFormat, id_and_flags.GetWireFormat(SPDY_VERSION_FOR_TESTS));
2621 }
2622
2623 } // namespace
OLDNEW
« no previous file with comments | « net/spdy/spdy_framer_spdy2_test.cc ('k') | net/spdy/spdy_framer_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698