Pass CreateDirectory errors up to IndexedDB.
[chromium-blink-merge.git] / net / spdy / spdy_framer_test.cc
blobd75dadbe05d90c9120d2fbeb5bb74c8afe86fa59
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.
5 #include <algorithm>
6 #include <iostream>
7 #include <limits>
9 #include "base/compiler_specific.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "net/spdy/spdy_frame_builder.h"
12 #include "net/spdy/spdy_framer.h"
13 #include "net/spdy/spdy_protocol.h"
14 #include "net/spdy/spdy_test_utils.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/platform_test.h"
18 using std::string;
19 using std::max;
20 using std::min;
21 using std::numeric_limits;
22 using testing::_;
24 namespace net {
26 namespace test {
28 static const size_t kMaxDecompressedSize = 1024;
30 // TODO(akalin): Make sure expectations on mocks are set before mock
31 // functions are called, as interleaving expectations and calls is
32 // undefined.
33 class MockVisitor : public SpdyFramerVisitorInterface {
34 public:
35 MOCK_METHOD1(OnError, void(SpdyFramer* framer));
36 MOCK_METHOD6(OnSynStream, void(SpdyStreamId stream_id,
37 SpdyStreamId associated_stream_id,
38 SpdyPriority priority,
39 uint8 slot,
40 bool fin,
41 bool unidirectional));
42 MOCK_METHOD2(OnSynReply, void(SpdyStreamId stream_id, bool fin));
43 MOCK_METHOD2(OnHeaders, void(SpdyStreamId stream_id, bool fin));
44 MOCK_METHOD3(OnControlFrameHeaderData, bool(SpdyStreamId stream_id,
45 const char* header_data,
46 size_t len));
47 MOCK_METHOD2(OnCredentialFrameData, bool(const char* credential_data,
48 size_t len));
49 MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId stream_id,
50 size_t length,
51 bool fin));
52 MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId stream_id,
53 const char* data,
54 size_t len,
55 bool fin));
56 MOCK_METHOD1(OnSettings, void(bool clear_persisted));
57 MOCK_METHOD3(OnSetting, void(SpdySettingsIds id, uint8 flags, uint32 value));
58 MOCK_METHOD1(OnPing, void(uint32 unique_id));
59 MOCK_METHOD2(OnRstStream, void(SpdyStreamId stream_id,
60 SpdyRstStreamStatus status));
61 MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id,
62 SpdyGoAwayStatus status));
63 MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId stream_id,
64 uint32 delta_window_size));
65 MOCK_METHOD2(OnSynStreamCompressed,
66 void(size_t uncompressed_length,
67 size_t compressed_length));
68 MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
71 class SpdyFramerTestUtil {
72 public:
73 // Decompress a single frame using the decompression context held by
74 // the SpdyFramer. The implemention is meant for use only in tests
75 // and will CHECK fail if the input is anything other than a single,
76 // well-formed compressed frame.
78 // Returns a new decompressed SpdyFrame.
79 template<class SpdyFrameType> static SpdyFrame* DecompressFrame(
80 SpdyFramer* framer, const SpdyFrameType& frame) {
81 DecompressionVisitor visitor(framer->protocol_version());
82 framer->set_visitor(&visitor);
83 CHECK_EQ(frame.size(), framer->ProcessInput(frame.data(), frame.size()));
84 CHECK_EQ(SpdyFramer::SPDY_RESET, framer->state());
85 framer->set_visitor(NULL);
87 char* buffer = visitor.ReleaseBuffer();
88 CHECK(buffer != NULL);
89 SpdyFrame* decompressed_frame = new SpdyFrame(buffer, visitor.size(), true);
90 if (framer->protocol_version() == 4) {
91 SetFrameLength(decompressed_frame,
92 visitor.size(),
93 framer->protocol_version());
94 } else {
95 SetFrameLength(decompressed_frame,
96 visitor.size() - framer->GetControlFrameHeaderSize(),
97 framer->protocol_version());
99 return decompressed_frame;
102 class DecompressionVisitor : public SpdyFramerVisitorInterface {
103 public:
104 explicit DecompressionVisitor(SpdyMajorVersion version)
105 : version_(version), size_(0), finished_(false) {}
107 void ResetBuffer() {
108 CHECK(buffer_.get() == NULL);
109 CHECK_EQ(0u, size_);
110 CHECK(!finished_);
111 buffer_.reset(new char[kMaxDecompressedSize]);
114 virtual void OnSynStream(SpdyStreamId stream_id,
115 SpdyStreamId associated_stream_id,
116 SpdyPriority priority,
117 uint8 slot,
118 bool fin,
119 bool unidirectional) OVERRIDE {
120 SpdyFramer framer(version_);
121 framer.set_enable_compression(false);
122 const SpdyHeaderBlock null_headers;
123 int flags = CONTROL_FLAG_NONE;
124 if (fin) {
125 flags &= CONTROL_FLAG_FIN;
127 if (unidirectional) {
128 flags &= CONTROL_FLAG_UNIDIRECTIONAL;
130 scoped_ptr<SpdyFrame> frame(
131 framer.CreateSynStream(stream_id,
132 associated_stream_id,
133 priority,
134 slot,
135 static_cast<SpdyControlFlags>(flags),
136 false,
137 &null_headers));
138 ResetBuffer();
139 memcpy(buffer_.get(), frame->data(), framer.GetSynStreamMinimumSize());
140 size_ += framer.GetSynStreamMinimumSize();
143 virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {
144 SpdyFramer framer(version_);
145 framer.set_enable_compression(false);
146 const SpdyHeaderBlock null_headers;
147 int flags = CONTROL_FLAG_NONE;
148 if (fin) {
149 flags &= CONTROL_FLAG_FIN;
151 scoped_ptr<SpdyFrame> frame(
152 framer.CreateHeaders(stream_id,
153 static_cast<SpdyControlFlags>(flags),
154 false,
155 &null_headers));
156 ResetBuffer();
157 memcpy(buffer_.get(), frame->data(), framer.GetHeadersMinimumSize());
158 size_ += framer.GetSynStreamMinimumSize();
161 virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE {
162 SpdyFramer framer(version_);
163 framer.set_enable_compression(false);
164 const SpdyHeaderBlock null_headers;
165 int flags = CONTROL_FLAG_NONE;
166 if (fin) {
167 flags &= CONTROL_FLAG_FIN;
169 scoped_ptr<SpdyFrame> frame(
170 framer.CreateHeaders(stream_id,
171 static_cast<SpdyControlFlags>(flags),
172 false,
173 &null_headers));
174 ResetBuffer();
175 memcpy(buffer_.get(), frame->data(), framer.GetHeadersMinimumSize());
176 size_ += framer.GetSynStreamMinimumSize();
179 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
180 const char* header_data,
181 size_t len) OVERRIDE {
182 CHECK(buffer_.get() != NULL);
183 CHECK_GE(kMaxDecompressedSize, size_ + len);
184 CHECK(!finished_);
185 if (len != 0) {
186 memcpy(buffer_.get() + size_, header_data, len);
187 size_ += len;
188 } else {
189 // Done.
190 finished_ = true;
192 return true;
195 virtual bool OnCredentialFrameData(const char* /*credential_data*/,
196 size_t /*len*/) OVERRIDE {
197 LOG(FATAL) << "Unexpected CREDENTIAL Frame";
198 return false;
201 virtual void OnError(SpdyFramer* framer) OVERRIDE { LOG(FATAL); }
202 virtual void OnDataFrameHeader(SpdyStreamId stream_id,
203 size_t length,
204 bool fin) OVERRIDE {
205 LOG(FATAL) << "Unexpected data frame header";
207 virtual void OnStreamFrameData(SpdyStreamId stream_id,
208 const char* data,
209 size_t len,
210 bool fin) OVERRIDE {
211 LOG(FATAL);
213 virtual void OnSetting(SpdySettingsIds id,
214 uint8 flags,
215 uint32 value) OVERRIDE {
216 LOG(FATAL);
218 virtual void OnSynStreamCompressed(
219 size_t uncompressed_size,
220 size_t compressed_size) OVERRIDE {
222 virtual void OnPing(uint32 unique_id) OVERRIDE {
223 LOG(FATAL);
225 virtual void OnRstStream(SpdyStreamId stream_id,
226 SpdyRstStreamStatus status) OVERRIDE {
227 LOG(FATAL);
229 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
230 SpdyGoAwayStatus status) OVERRIDE {
231 LOG(FATAL);
233 virtual void OnWindowUpdate(SpdyStreamId stream_id,
234 uint32 delta_window_size) OVERRIDE {
235 LOG(FATAL);
238 char* ReleaseBuffer() {
239 CHECK(finished_);
240 return buffer_.release();
243 size_t size() const {
244 CHECK(finished_);
245 return size_;
248 private:
249 SpdyMajorVersion version_;
250 scoped_ptr<char[]> buffer_;
251 size_t size_;
252 bool finished_;
254 DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor);
257 private:
258 DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil);
261 class TestSpdyVisitor : public SpdyFramerVisitorInterface,
262 public SpdyFramerDebugVisitorInterface {
263 public:
264 static const size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024;
265 static const size_t kDefaultCredentialBufferSize = 16 * 1024;
267 explicit TestSpdyVisitor(SpdyMajorVersion version)
268 : framer_(version),
269 use_compression_(false),
270 error_count_(0),
271 syn_frame_count_(0),
272 syn_reply_frame_count_(0),
273 headers_frame_count_(0),
274 goaway_count_(0),
275 setting_count_(0),
276 last_window_update_stream_(0),
277 last_window_update_delta_(0),
278 data_bytes_(0),
279 fin_frame_count_(0),
280 fin_flag_count_(0),
281 zero_length_data_frame_count_(0),
282 control_frame_header_data_count_(0),
283 zero_length_control_frame_header_data_count_(0),
284 data_frame_count_(0),
285 last_payload_len_(0),
286 last_frame_len_(0),
287 header_buffer_(new char[kDefaultHeaderBufferSize]),
288 header_buffer_length_(0),
289 header_buffer_size_(kDefaultHeaderBufferSize),
290 header_stream_id_(-1),
291 header_control_type_(DATA),
292 header_buffer_valid_(false),
293 credential_buffer_(new char[kDefaultCredentialBufferSize]),
294 credential_buffer_length_(0),
295 credential_buffer_size_(kDefaultCredentialBufferSize) {
298 virtual void OnError(SpdyFramer* f) OVERRIDE {
299 LOG(INFO) << "SpdyFramer Error: "
300 << SpdyFramer::ErrorCodeToString(f->error_code());
301 error_count_++;
304 virtual void OnDataFrameHeader(SpdyStreamId stream_id,
305 size_t length,
306 bool fin) OVERRIDE {
307 data_frame_count_++;
308 header_stream_id_ = stream_id;
311 virtual void OnStreamFrameData(SpdyStreamId stream_id,
312 const char* data,
313 size_t len,
314 bool fin) OVERRIDE {
315 EXPECT_EQ(header_stream_id_, stream_id);
316 if (len == 0)
317 ++zero_length_data_frame_count_;
319 data_bytes_ += len;
320 std::cerr << "OnStreamFrameData(" << stream_id << ", \"";
321 if (len > 0) {
322 for (size_t i = 0 ; i < len; ++i) {
323 std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec;
326 std::cerr << "\", " << len << ")\n";
329 virtual void OnSynStream(SpdyStreamId stream_id,
330 SpdyStreamId associated_stream_id,
331 SpdyPriority priority,
332 uint8 credential_slot,
333 bool fin,
334 bool unidirectional) OVERRIDE {
335 syn_frame_count_++;
336 InitHeaderStreaming(SYN_STREAM, stream_id);
337 if (fin) {
338 fin_flag_count_++;
342 virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {
343 syn_reply_frame_count_++;
344 InitHeaderStreaming(HEADERS, stream_id);
345 if (fin) {
346 fin_flag_count_++;
350 virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE {
351 headers_frame_count_++;
352 InitHeaderStreaming(SYN_REPLY, stream_id);
353 if (fin) {
354 fin_flag_count_++;
358 virtual void OnSetting(SpdySettingsIds id,
359 uint8 flags,
360 uint32 value) OVERRIDE {
361 setting_count_++;
364 virtual void OnSynStreamCompressed(
365 size_t uncompressed_size,
366 size_t compressed_size) OVERRIDE {
369 virtual void OnPing(uint32 unique_id) OVERRIDE {
370 DLOG(FATAL);
373 virtual void OnRstStream(SpdyStreamId stream_id,
374 SpdyRstStreamStatus status) OVERRIDE {
375 fin_frame_count_++;
378 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
379 SpdyGoAwayStatus status) OVERRIDE {
380 goaway_count_++;
383 virtual void OnWindowUpdate(SpdyStreamId stream_id,
384 uint32 delta_window_size) OVERRIDE {
385 last_window_update_stream_ = stream_id;
386 last_window_update_delta_ = delta_window_size;
389 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
390 const char* header_data,
391 size_t len) OVERRIDE {
392 ++control_frame_header_data_count_;
393 CHECK_EQ(header_stream_id_, stream_id);
394 if (len == 0) {
395 ++zero_length_control_frame_header_data_count_;
396 // Indicates end-of-header-block.
397 CHECK(header_buffer_valid_);
398 size_t parsed_length = framer_.ParseHeaderBlockInBuffer(
399 header_buffer_.get(), header_buffer_length_, &headers_);
400 DCHECK_EQ(header_buffer_length_, parsed_length);
401 return true;
403 const size_t available = header_buffer_size_ - header_buffer_length_;
404 if (len > available) {
405 header_buffer_valid_ = false;
406 return false;
408 memcpy(header_buffer_.get() + header_buffer_length_, header_data, len);
409 header_buffer_length_ += len;
410 return true;
413 virtual bool OnCredentialFrameData(const char* credential_data,
414 size_t len) OVERRIDE {
415 if (len == 0) {
416 if (!framer_.ParseCredentialData(credential_buffer_.get(),
417 credential_buffer_length_,
418 &credential_)) {
419 ++error_count_;
421 return true;
423 const size_t available =
424 credential_buffer_size_ - credential_buffer_length_;
425 if (len > available) {
426 return false;
428 memcpy(credential_buffer_.get() + credential_buffer_length_,
429 credential_data, len);
430 credential_buffer_length_ += len;
431 return true;
434 virtual void OnSendCompressedFrame(SpdyStreamId stream_id,
435 SpdyFrameType type,
436 size_t payload_len,
437 size_t frame_len) OVERRIDE {
438 last_payload_len_ = payload_len;
439 last_frame_len_ = frame_len;
442 virtual void OnReceiveCompressedFrame(SpdyStreamId stream_id,
443 SpdyFrameType type,
444 size_t frame_len) OVERRIDE {
445 last_frame_len_ = frame_len;
448 // Convenience function which runs a framer simulation with particular input.
449 void SimulateInFramer(const unsigned char* input, size_t size) {
450 framer_.set_enable_compression(use_compression_);
451 framer_.set_visitor(this);
452 size_t input_remaining = size;
453 const char* input_ptr = reinterpret_cast<const char*>(input);
454 while (input_remaining > 0 &&
455 framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) {
456 // To make the tests more interesting, we feed random (amd small) chunks
457 // into the framer. This simulates getting strange-sized reads from
458 // the socket.
459 const size_t kMaxReadSize = 32;
460 size_t bytes_read =
461 (rand() % min(input_remaining, kMaxReadSize)) + 1;
462 size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read);
463 input_remaining -= bytes_processed;
464 input_ptr += bytes_processed;
468 void InitHeaderStreaming(SpdyFrameType header_control_type,
469 SpdyStreamId stream_id) {
470 DCHECK_GE(header_control_type, FIRST_CONTROL_TYPE);
471 DCHECK_LE(header_control_type, LAST_CONTROL_TYPE);
472 memset(header_buffer_.get(), 0, header_buffer_size_);
473 header_buffer_length_ = 0;
474 header_stream_id_ = stream_id;
475 header_control_type_ = header_control_type;
476 header_buffer_valid_ = true;
477 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
480 // Override the default buffer size (16K). Call before using the framer!
481 void set_header_buffer_size(size_t header_buffer_size) {
482 header_buffer_size_ = header_buffer_size;
483 header_buffer_.reset(new char[header_buffer_size]);
486 static size_t header_data_chunk_max_size() {
487 return SpdyFramer::kHeaderDataChunkMaxSize;
490 SpdyFramer framer_;
491 bool use_compression_;
493 // Counters from the visitor callbacks.
494 int error_count_;
495 int syn_frame_count_;
496 int syn_reply_frame_count_;
497 int headers_frame_count_;
498 int goaway_count_;
499 int setting_count_;
500 SpdyStreamId last_window_update_stream_;
501 uint32 last_window_update_delta_;
502 int data_bytes_;
503 int fin_frame_count_; // The count of RST_STREAM type frames received.
504 int fin_flag_count_; // The count of frames with the FIN flag set.
505 int zero_length_data_frame_count_; // The count of zero-length data frames.
506 int control_frame_header_data_count_; // The count of chunks received.
507 // The count of zero-length control frame header data chunks received.
508 int zero_length_control_frame_header_data_count_;
509 int data_frame_count_;
510 size_t last_payload_len_;
511 size_t last_frame_len_;
513 // Header block streaming state:
514 scoped_ptr<char[]> header_buffer_;
515 size_t header_buffer_length_;
516 size_t header_buffer_size_;
517 SpdyStreamId header_stream_id_;
518 SpdyFrameType header_control_type_;
519 bool header_buffer_valid_;
520 SpdyHeaderBlock headers_;
522 scoped_ptr<char[]> credential_buffer_;
523 size_t credential_buffer_length_;
524 size_t credential_buffer_size_;
525 SpdyCredential credential_;
528 // Retrieves serialized headers from SYN_STREAM frame.
529 // Does not check that the given frame is a SYN_STREAM.
530 base::StringPiece GetSerializedHeaders(const SpdyFrame* frame,
531 const SpdyFramer& framer) {
532 return base::StringPiece(frame->data() + framer.GetSynStreamMinimumSize(),
533 frame->size() - framer.GetSynStreamMinimumSize());
536 } // namespace test
538 } // namespace net
540 using net::test::SetFrameLength;
541 using net::test::SetFrameFlags;
542 using net::test::CompareCharArraysWithHexError;
543 using net::test::SpdyFramerTestUtil;
544 using net::test::TestSpdyVisitor;
545 using net::test::GetSerializedHeaders;
547 namespace net {
549 class SpdyFramerTest : public ::testing::TestWithParam<SpdyMajorVersion> {
550 protected:
551 virtual void SetUp() {
552 spdy_version_ = GetParam();
553 spdy_version_ch_ = static_cast<unsigned char>(spdy_version_);
556 void CompareFrame(const string& description,
557 const SpdyFrame& actual_frame,
558 const unsigned char* expected,
559 const int expected_len) {
560 const unsigned char* actual =
561 reinterpret_cast<const unsigned char*>(actual_frame.data());
562 CompareCharArraysWithHexError(
563 description, actual, actual_frame.size(), expected, expected_len);
566 void CompareFrames(const string& description,
567 const SpdyFrame& expected_frame,
568 const SpdyFrame& actual_frame) {
569 CompareCharArraysWithHexError(
570 description,
571 reinterpret_cast<const unsigned char*>(expected_frame.data()),
572 expected_frame.size(),
573 reinterpret_cast<const unsigned char*>(actual_frame.data()),
574 actual_frame.size());
577 // Returns true if the two header blocks have equivalent content.
578 bool CompareHeaderBlocks(const SpdyHeaderBlock* expected,
579 const SpdyHeaderBlock* actual) {
580 if (expected->size() != actual->size()) {
581 LOG(ERROR) << "Expected " << expected->size() << " headers; actually got "
582 << actual->size() << ".";
583 return false;
585 for (SpdyHeaderBlock::const_iterator it = expected->begin();
586 it != expected->end();
587 ++it) {
588 SpdyHeaderBlock::const_iterator it2 = actual->find(it->first);
589 if (it2 == actual->end()) {
590 LOG(ERROR) << "Expected header name '" << it->first << "'.";
591 return false;
593 if (it->second.compare(it2->second) != 0) {
594 LOG(ERROR) << "Expected header named '" << it->first
595 << "' to have a value of '" << it->second
596 << "'. The actual value received was '" << it2->second
597 << "'.";
598 return false;
601 return true;
604 void AddSpdySettingFromWireFormat(SettingsMap* settings,
605 uint32 key,
606 uint32 value) {
607 SettingsFlagsAndId flags_and_id =
608 SettingsFlagsAndId::FromWireFormat(spdy_version_, key);
609 SpdySettingsIds id = static_cast<SpdySettingsIds>(flags_and_id.id());
610 SpdySettingsFlags flags =
611 static_cast<SpdySettingsFlags>(flags_and_id.flags());
612 CHECK(settings->find(id) == settings->end());
613 settings->insert(std::make_pair(id, SettingsFlagsAndValue(flags, value)));
616 bool IsSpdy2() { return spdy_version_ == SPDY2; }
617 bool IsSpdy3() { return spdy_version_ == SPDY3; }
618 bool IsSpdy4() { return spdy_version_ == SPDY4; }
620 // Version of SPDY protocol to be used.
621 SpdyMajorVersion spdy_version_;
622 unsigned char spdy_version_ch_;
625 // All tests are run with two different SPDY versions: SPDY/2 and SPDY/3.
626 INSTANTIATE_TEST_CASE_P(SpdyFramerTests,
627 SpdyFramerTest,
628 ::testing::Values(SPDY2, SPDY3, SPDY4));
630 // Test that we can encode and decode a SpdyHeaderBlock in serialized form.
631 TEST_P(SpdyFramerTest, HeaderBlockInBuffer) {
632 SpdyHeaderBlock headers;
633 headers["alpha"] = "beta";
634 headers["gamma"] = "charlie";
635 SpdyFramer framer(spdy_version_);
636 framer.set_enable_compression(false);
638 // Encode the header block into a SynStream frame.
639 scoped_ptr<SpdyFrame> frame(
640 framer.CreateSynStream(1, // stream id
641 0, // associated stream id
642 1, // priority
643 0, // credential slot
644 CONTROL_FLAG_NONE,
645 false, // compress
646 &headers));
647 EXPECT_TRUE(frame.get() != NULL);
648 base::StringPiece serialized_headers =
649 GetSerializedHeaders(frame.get(), framer);
650 SpdyHeaderBlock new_headers;
651 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
652 serialized_headers.size(),
653 &new_headers));
655 EXPECT_EQ(headers.size(), new_headers.size());
656 EXPECT_EQ(headers["alpha"], new_headers["alpha"]);
657 EXPECT_EQ(headers["gamma"], new_headers["gamma"]);
660 // Test that if there's not a full frame, we fail to parse it.
661 TEST_P(SpdyFramerTest, UndersizedHeaderBlockInBuffer) {
662 SpdyHeaderBlock headers;
663 headers["alpha"] = "beta";
664 headers["gamma"] = "charlie";
665 SpdyFramer framer(spdy_version_);
666 framer.set_enable_compression(false);
668 // Encode the header block into a SynStream frame.
669 scoped_ptr<SpdyFrame> frame(
670 framer.CreateSynStream(1, // stream id
671 0, // associated stream id
672 1, // priority
673 0, // credential slot
674 CONTROL_FLAG_NONE,
675 false, // compress
676 &headers));
677 EXPECT_TRUE(frame.get() != NULL);
679 base::StringPiece serialized_headers =
680 GetSerializedHeaders(frame.get(), framer);
681 SpdyHeaderBlock new_headers;
682 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
683 serialized_headers.size() - 2,
684 &new_headers));
687 TEST_P(SpdyFramerTest, OutOfOrderHeaders) {
688 SpdyFramer framer(spdy_version_);
689 framer.set_enable_compression(false);
691 // Frame builder with plentiful buffer size.
692 SpdyFrameBuilder frame(1024);
693 if (spdy_version_ < 4) {
694 frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
695 frame.WriteUInt32(3); // stream_id
696 } else {
697 frame.WriteFramePrefix(framer, SYN_STREAM, CONTROL_FLAG_NONE, 3);
700 frame.WriteUInt32(0); // Associated stream id
701 frame.WriteUInt16(0); // Priority.
703 if (IsSpdy2()) {
704 frame.WriteUInt16(2); // Number of headers.
705 frame.WriteString("gamma");
706 frame.WriteString("gamma");
707 frame.WriteString("alpha");
708 frame.WriteString("alpha");
709 } else {
710 frame.WriteUInt32(2); // Number of headers.
711 frame.WriteStringPiece32("gamma");
712 frame.WriteStringPiece32("gamma");
713 frame.WriteStringPiece32("alpha");
714 frame.WriteStringPiece32("alpha");
716 // write the length
717 frame.RewriteLength(framer);
719 SpdyHeaderBlock new_headers;
720 scoped_ptr<SpdyFrame> control_frame(frame.take());
721 base::StringPiece serialized_headers =
722 GetSerializedHeaders(control_frame.get(), framer);
723 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
724 serialized_headers.size(),
725 &new_headers));
728 TEST_P(SpdyFramerTest, CreateCredential) {
729 SpdyFramer framer(spdy_version_);
732 const char kDescription[] = "CREDENTIAL frame";
733 const unsigned char kV3FrameData[] = { // Also applies for V2.
734 0x80, spdy_version_ch_, 0x00, 0x0A,
735 0x00, 0x00, 0x00, 0x33,
736 0x00, 0x03, 0x00, 0x00,
737 0x00, 0x05, 'p', 'r',
738 'o', 'o', 'f', 0x00,
739 0x00, 0x00, 0x06, 'a',
740 ' ', 'c', 'e', 'r',
741 't', 0x00, 0x00, 0x00,
742 0x0C, 'a', 'n', 'o',
743 't', 'h', 'e', 'r',
744 ' ', 'c', 'e', 'r',
745 't', 0x00, 0x00, 0x00,
746 0x0A, 'f', 'i', 'n',
747 'a', 'l', ' ', 'c',
748 'e', 'r', 't',
750 const unsigned char kV4FrameData[] = {
751 0x00, 0x3b, 0x0A, 0x00,
752 0x00, 0x00, 0x00, 0x00,
753 0x00, 0x03, 0x00, 0x00,
754 0x00, 0x05, 'p', 'r',
755 'o', 'o', 'f', 0x00,
756 0x00, 0x00, 0x06, 'a',
757 ' ', 'c', 'e', 'r',
758 't', 0x00, 0x00, 0x00,
759 0x0C, 'a', 'n', 'o',
760 't', 'h', 'e', 'r',
761 ' ', 'c', 'e', 'r',
762 't', 0x00, 0x00, 0x00,
763 0x0A, 'f', 'i', 'n',
764 'a', 'l', ' ', 'c',
765 'e', 'r', 't',
767 SpdyCredential credential;
768 credential.slot = 3;
769 credential.proof = "proof";
770 credential.certs.push_back("a cert");
771 credential.certs.push_back("another cert");
772 credential.certs.push_back("final cert");
773 scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential));
774 if (IsSpdy4()) {
775 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
776 } else {
777 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
782 TEST_P(SpdyFramerTest, ParseCredentialFrameData) {
783 SpdyFramer framer(spdy_version_);
786 const unsigned char kV3FrameData[] = { // Also applies for V2.
787 0x80, spdy_version_ch_, 0x00, 0x0A,
788 0x00, 0x00, 0x00, 0x33,
789 0x00, 0x03, 0x00, 0x00,
790 0x00, 0x05, 'p', 'r',
791 'o', 'o', 'f', 0x00,
792 0x00, 0x00, 0x06, 'a',
793 ' ', 'c', 'e', 'r',
794 't', 0x00, 0x00, 0x00,
795 0x0C, 'a', 'n', 'o',
796 't', 'h', 'e', 'r',
797 ' ', 'c', 'e', 'r',
798 't', 0x00, 0x00, 0x00,
799 0x0A, 'f', 'i', 'n',
800 'a', 'l', ' ', 'c',
801 'e', 'r', 't',
803 const unsigned char kV4FrameData[] = {
804 0x00, 0x37, 0x0A, 0x00,
805 0x00, 0x00, 0x00, 0x00,
806 0x00, 0x03, 0x00, 0x00,
807 0x00, 0x05, 'p', 'r',
808 'o', 'o', 'f', 0x00,
809 0x00, 0x00, 0x06, 'a',
810 ' ', 'c', 'e', 'r',
811 't', 0x00, 0x00, 0x00,
812 0x0C, 'a', 'n', 'o',
813 't', 'h', 'e', 'r',
814 ' ', 'c', 'e', 'r',
815 't', 0x00, 0x00, 0x00,
816 0x0A, 'f', 'i', 'n',
817 'a', 'l', ' ', 'c',
818 'e', 'r', 't',
821 SpdyCredential credential;
822 if (IsSpdy4()) {
823 EXPECT_TRUE(SpdyFramer::ParseCredentialData(
824 reinterpret_cast<const char*>(kV4FrameData) +
825 framer.GetControlFrameHeaderSize(),
826 arraysize(kV4FrameData) - framer.GetControlFrameHeaderSize(),
827 &credential));
828 } else {
829 EXPECT_TRUE(SpdyFramer::ParseCredentialData(
830 reinterpret_cast<const char*>(kV3FrameData) +
831 framer.GetControlFrameHeaderSize(),
832 arraysize(kV3FrameData) - framer.GetControlFrameHeaderSize(),
833 &credential));
835 EXPECT_EQ(3u, credential.slot);
836 EXPECT_EQ("proof", credential.proof);
837 EXPECT_EQ("a cert", credential.certs.front());
838 credential.certs.erase(credential.certs.begin());
839 EXPECT_EQ("another cert", credential.certs.front());
840 credential.certs.erase(credential.certs.begin());
841 EXPECT_EQ("final cert", credential.certs.front());
842 credential.certs.erase(credential.certs.begin());
843 EXPECT_TRUE(credential.certs.empty());
847 TEST_P(SpdyFramerTest, DuplicateHeader) {
848 SpdyFramer framer(spdy_version_);
849 // Frame builder with plentiful buffer size.
850 SpdyFrameBuilder frame(1024);
851 if (spdy_version_ < 4) {
852 frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
853 frame.WriteUInt32(3); // stream_id
854 } else {
855 frame.WriteFramePrefix(framer, SYN_STREAM, CONTROL_FLAG_NONE, 3);
858 frame.WriteUInt32(0); // associated stream id
859 frame.WriteUInt16(0); // Priority.
861 if (IsSpdy2()) {
862 frame.WriteUInt16(2); // Number of headers.
863 frame.WriteString("name");
864 frame.WriteString("value1");
865 frame.WriteString("name");
866 frame.WriteString("value2");
867 } else {
868 frame.WriteUInt32(2); // Number of headers.
869 frame.WriteStringPiece32("name");
870 frame.WriteStringPiece32("value1");
871 frame.WriteStringPiece32("name");
872 frame.WriteStringPiece32("value2");
874 // write the length
875 frame.RewriteLength(framer);
877 SpdyHeaderBlock new_headers;
878 framer.set_enable_compression(false);
879 scoped_ptr<SpdyFrame> control_frame(frame.take());
880 base::StringPiece serialized_headers =
881 GetSerializedHeaders(control_frame.get(), framer);
882 // This should fail because duplicate headers are verboten by the spec.
883 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
884 serialized_headers.size(),
885 &new_headers));
888 TEST_P(SpdyFramerTest, MultiValueHeader) {
889 SpdyFramer framer(spdy_version_);
890 // Frame builder with plentiful buffer size.
891 SpdyFrameBuilder frame(1024);
892 if (spdy_version_ < 4) {
893 frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
894 frame.WriteUInt32(3); // stream_id
895 } else {
896 frame.WriteFramePrefix(framer, SYN_STREAM, CONTROL_FLAG_NONE, 3);
899 frame.WriteUInt32(0); // associated stream id
900 frame.WriteUInt16(0); // Priority.
902 string value("value1\0value2");
903 if (IsSpdy2()) {
904 frame.WriteUInt16(1); // Number of headers.
905 frame.WriteString("name");
906 frame.WriteString(value);
907 } else {
908 frame.WriteUInt32(1); // Number of headers.
909 frame.WriteStringPiece32("name");
910 frame.WriteStringPiece32(value);
912 // write the length
913 frame.RewriteLength(framer);
915 SpdyHeaderBlock new_headers;
916 framer.set_enable_compression(false);
917 scoped_ptr<SpdyFrame> control_frame(frame.take());
918 base::StringPiece serialized_headers =
919 GetSerializedHeaders(control_frame.get(), framer);
920 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
921 serialized_headers.size(),
922 &new_headers));
923 EXPECT_TRUE(new_headers.find("name") != new_headers.end());
924 EXPECT_EQ(value, new_headers.find("name")->second);
927 TEST_P(SpdyFramerTest, BasicCompression) {
928 SpdyHeaderBlock headers;
929 headers["server"] = "SpdyServer 1.0";
930 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST";
931 headers["status"] = "200";
932 headers["version"] = "HTTP/1.1";
933 headers["content-type"] = "text/html";
934 headers["content-length"] = "12";
936 scoped_ptr<TestSpdyVisitor> visitor(new TestSpdyVisitor(spdy_version_));
937 SpdyFramer framer(spdy_version_);
938 framer.set_debug_visitor(visitor.get());
939 scoped_ptr<SpdyFrame> frame1(
940 framer.CreateSynStream(1, // stream id
941 0, // associated stream id
942 1, // priority
943 0, // credential slot
944 CONTROL_FLAG_NONE,
945 true, // compress
946 &headers));
947 size_t uncompressed_size1 = visitor->last_payload_len_;
948 size_t compressed_size1 =
949 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize();
950 if (IsSpdy2()) {
951 EXPECT_EQ(139u, uncompressed_size1);
952 #if defined(USE_SYSTEM_ZLIB)
953 EXPECT_EQ(155u, compressed_size1);
954 #else // !defined(USE_SYSTEM_ZLIB)
955 EXPECT_EQ(135u, compressed_size1);
956 #endif // !defined(USE_SYSTEM_ZLIB)
957 } else {
958 EXPECT_EQ(165u, uncompressed_size1);
959 #if defined(USE_SYSTEM_ZLIB)
960 EXPECT_EQ(181u, compressed_size1);
961 #else // !defined(USE_SYSTEM_ZLIB)
962 EXPECT_EQ(117u, compressed_size1);
963 #endif // !defined(USE_SYSTEM_ZLIB)
965 scoped_ptr<SpdyFrame> frame2(
966 framer.CreateSynStream(1, // stream id
967 0, // associated stream id
968 1, // priority
969 0, // credential slot
970 CONTROL_FLAG_NONE,
971 true, // compress
972 &headers));
973 size_t uncompressed_size2 = visitor->last_payload_len_;
974 size_t compressed_size2 =
975 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize();
977 // Expect the second frame to be more compact than the first.
978 EXPECT_LE(frame2->size(), frame1->size());
980 // Decompress the first frame
981 scoped_ptr<SpdyFrame> frame3(SpdyFramerTestUtil::DecompressFrame(
982 &framer, *frame1.get()));
984 // Decompress the second frame
985 visitor.reset(new TestSpdyVisitor(spdy_version_));
986 framer.set_debug_visitor(visitor.get());
987 scoped_ptr<SpdyFrame> frame4(SpdyFramerTestUtil::DecompressFrame(
988 &framer, *frame2.get()));
989 size_t uncompressed_size4 =
990 frame4->size() - framer.GetSynStreamMinimumSize();
991 size_t compressed_size4 =
992 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize();
993 if (IsSpdy2()) {
994 EXPECT_EQ(139u, uncompressed_size4);
995 #if defined(USE_SYSTEM_ZLIB)
996 EXPECT_EQ(149u, compressed_size4);
997 #else // !defined(USE_SYSTEM_ZLIB)
998 EXPECT_EQ(101u, compressed_size4);
999 #endif // !defined(USE_SYSTEM_ZLIB)
1000 } else {
1001 EXPECT_EQ(165u, uncompressed_size4);
1002 #if defined(USE_SYSTEM_ZLIB)
1003 EXPECT_EQ(175u, compressed_size4);
1004 #else // !defined(USE_SYSTEM_ZLIB)
1005 EXPECT_EQ(102u, compressed_size4);
1006 #endif // !defined(USE_SYSTEM_ZLIB)
1009 EXPECT_EQ(uncompressed_size1, uncompressed_size2);
1010 EXPECT_EQ(uncompressed_size1, uncompressed_size4);
1011 EXPECT_EQ(compressed_size2, compressed_size4);
1013 // Expect frames 3 & 4 to be the same.
1014 CompareFrames("Uncompressed SYN_STREAM", *frame3, *frame4);
1016 // Expect frames 3 to be the same as a uncompressed frame created
1017 // from scratch.
1018 framer.set_enable_compression(false);
1019 scoped_ptr<SpdyFrame> uncompressed_frame(
1020 framer.CreateSynStream(1, // stream id
1021 0, // associated stream id
1022 1, // priority
1023 0, // credential slot
1024 CONTROL_FLAG_NONE,
1025 false, // compress
1026 &headers));
1027 CompareFrames("Uncompressed SYN_STREAM", *frame3, *uncompressed_frame);
1030 TEST_P(SpdyFramerTest, CompressEmptyHeaders) {
1031 // See crbug.com/172383
1032 SpdyHeaderBlock headers;
1033 headers["server"] = "SpdyServer 1.0";
1034 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST";
1035 headers["status"] = "200";
1036 headers["version"] = "HTTP/1.1";
1037 headers["content-type"] = "text/html";
1038 headers["content-length"] = "12";
1039 headers["x-empty-header"] = "";
1041 SpdyFramer framer(spdy_version_);
1042 framer.set_enable_compression(true);
1043 scoped_ptr<SpdyFrame> frame1(
1044 framer.CreateSynStream(1, // stream id
1045 0, // associated stream id
1046 1, // priority
1047 0, // credential slot
1048 CONTROL_FLAG_NONE,
1049 true, // compress
1050 &headers));
1053 TEST_P(SpdyFramerTest, Basic) {
1054 const unsigned char kV2Input[] = {
1055 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1
1056 0x00, 0x00, 0x00, 0x14,
1057 0x00, 0x00, 0x00, 0x01,
1058 0x00, 0x00, 0x00, 0x00,
1059 0x00, 0x00, 0x00, 0x01,
1060 0x00, 0x02, 'h', 'h',
1061 0x00, 0x02, 'v', 'v',
1063 0x80, spdy_version_ch_, 0x00, 0x08, // HEADERS on Stream #1
1064 0x00, 0x00, 0x00, 0x18,
1065 0x00, 0x00, 0x00, 0x01,
1066 0x00, 0x00, 0x00, 0x02,
1067 0x00, 0x02, 'h', '2',
1068 0x00, 0x02, 'v', '2',
1069 0x00, 0x02, 'h', '3',
1070 0x00, 0x02, 'v', '3',
1072 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1073 0x00, 0x00, 0x00, 0x0c,
1074 0xde, 0xad, 0xbe, 0xef,
1075 0xde, 0xad, 0xbe, 0xef,
1076 0xde, 0xad, 0xbe, 0xef,
1078 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #3
1079 0x00, 0x00, 0x00, 0x0c,
1080 0x00, 0x00, 0x00, 0x03,
1081 0x00, 0x00, 0x00, 0x00,
1082 0x00, 0x00, 0x00, 0x00,
1084 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
1085 0x00, 0x00, 0x00, 0x08,
1086 0xde, 0xad, 0xbe, 0xef,
1087 0xde, 0xad, 0xbe, 0xef,
1089 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1090 0x00, 0x00, 0x00, 0x04,
1091 0xde, 0xad, 0xbe, 0xef,
1093 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #1
1094 0x00, 0x00, 0x00, 0x08,
1095 0x00, 0x00, 0x00, 0x01,
1096 0x00, 0x00, 0x00, 0x00,
1098 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
1099 0x00, 0x00, 0x00, 0x00,
1101 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #3
1102 0x00, 0x00, 0x00, 0x08,
1103 0x00, 0x00, 0x00, 0x03,
1104 0x00, 0x00, 0x00, 0x00,
1107 const unsigned char kV3Input[] = {
1108 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1
1109 0x00, 0x00, 0x00, 0x1a,
1110 0x00, 0x00, 0x00, 0x01,
1111 0x00, 0x00, 0x00, 0x00,
1112 0x00, 0x00, 0x00, 0x00,
1113 0x00, 0x01, 0x00, 0x00,
1114 0x00, 0x02, 'h', 'h',
1115 0x00, 0x00, 0x00, 0x02,
1116 'v', 'v',
1118 0x80, spdy_version_ch_, 0x00, 0x08, // HEADERS on Stream #1
1119 0x00, 0x00, 0x00, 0x20,
1120 0x00, 0x00, 0x00, 0x01,
1121 0x00, 0x00, 0x00, 0x02,
1122 0x00, 0x00, 0x00, 0x02,
1123 'h', '2',
1124 0x00, 0x00, 0x00, 0x02,
1125 'v', '2', 0x00, 0x00,
1126 0x00, 0x02, 'h', '3',
1127 0x00, 0x00, 0x00, 0x02,
1128 'v', '3',
1130 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1131 0x00, 0x00, 0x00, 0x0c,
1132 0xde, 0xad, 0xbe, 0xef,
1133 0xde, 0xad, 0xbe, 0xef,
1134 0xde, 0xad, 0xbe, 0xef,
1136 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #3
1137 0x00, 0x00, 0x00, 0x0e,
1138 0x00, 0x00, 0x00, 0x03,
1139 0x00, 0x00, 0x00, 0x00,
1140 0x00, 0x00, 0x00, 0x00,
1141 0x00, 0x00,
1143 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
1144 0x00, 0x00, 0x00, 0x08,
1145 0xde, 0xad, 0xbe, 0xef,
1146 0xde, 0xad, 0xbe, 0xef,
1148 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1149 0x00, 0x00, 0x00, 0x04,
1150 0xde, 0xad, 0xbe, 0xef,
1152 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #1
1153 0x00, 0x00, 0x00, 0x08,
1154 0x00, 0x00, 0x00, 0x01,
1155 0x00, 0x00, 0x00, 0x00,
1157 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
1158 0x00, 0x00, 0x00, 0x00,
1160 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #3
1161 0x00, 0x00, 0x00, 0x08,
1162 0x00, 0x00, 0x00, 0x03,
1163 0x00, 0x00, 0x00, 0x00,
1166 const unsigned char kV4Input[] = {
1167 0x00, 0x1e, 0x01, 0x00, // SYN_STREAM #1
1168 0x00, 0x00, 0x00, 0x01,
1169 0x00, 0x00, 0x00, 0x00,
1170 0x00, 0x00, 0x00, 0x00,
1171 0x00, 0x01, 0x00, 0x00,
1172 0x00, 0x02, 'h', 'h',
1173 0x00, 0x00, 0x00, 0x02,
1174 'v', 'v',
1176 0x00, 0x24, 0x08, 0x00, // HEADERS on Stream #1
1177 0x00, 0x00, 0x00, 0x01,
1178 0x00, 0x00, 0x00, 0x02,
1179 0x00, 0x00, 0x00, 0x02,
1180 'h', '2', 0x00, 0x00,
1181 0x00, 0x02, 'v', '2',
1182 0x00, 0x00, 0x00, 0x02,
1183 'h', '3', 0x00, 0x00,
1184 0x00, 0x02, 'v', '3',
1186 0x00, 0x14, 0x00, 0x00, // DATA on Stream #1
1187 0x00, 0x00, 0x00, 0x01,
1188 0xde, 0xad, 0xbe, 0xef,
1189 0xde, 0xad, 0xbe, 0xef,
1190 0xde, 0xad, 0xbe, 0xef,
1192 0x00, 0x12, 0x01, 0x00, // SYN Stream #3
1193 0x00, 0x00, 0x00, 0x03,
1194 0x00, 0x00, 0x00, 0x00,
1195 0x00, 0x00, 0x00, 0x00,
1196 0x00, 0x00,
1198 0x00, 0x10, 0x00, 0x00, // DATA on Stream #3
1199 0x00, 0x00, 0x00, 0x03,
1200 0xde, 0xad, 0xbe, 0xef,
1201 0xde, 0xad, 0xbe, 0xef,
1203 0x00, 0x0c, 0x00, 0x00, // DATA on Stream #1
1204 0x00, 0x00, 0x00, 0x01,
1205 0xde, 0xad, 0xbe, 0xef,
1207 0x00, 0x0c, 0x03, 0x00, // RST_STREAM on Stream #1
1208 0x00, 0x00, 0x00, 0x01,
1209 0x00, 0x00, 0x00, 0x00,
1211 0x00, 0x08, 0x00, 0x00, // DATA on Stream #3
1212 0x00, 0x00, 0x00, 0x03,
1214 0x00, 0x0c, 0x03, 0x00, // RST_STREAM on Stream #3
1215 0x00, 0x00, 0x00, 0x03,
1216 0x00, 0x00, 0x00, 0x00,
1219 TestSpdyVisitor visitor(spdy_version_);
1220 if (IsSpdy2()) {
1221 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
1222 } else if (IsSpdy3()) {
1223 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
1224 } else {
1225 visitor.SimulateInFramer(kV4Input, sizeof(kV4Input));
1228 EXPECT_EQ(0, visitor.error_count_);
1229 EXPECT_EQ(2, visitor.syn_frame_count_);
1230 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1231 EXPECT_EQ(1, visitor.headers_frame_count_);
1232 EXPECT_EQ(24, visitor.data_bytes_);
1233 EXPECT_EQ(2, visitor.fin_frame_count_);
1234 EXPECT_EQ(0, visitor.fin_flag_count_);
1235 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
1236 EXPECT_EQ(4, visitor.data_frame_count_);
1239 // Test that the FIN flag on a data frame signifies EOF.
1240 TEST_P(SpdyFramerTest, FinOnDataFrame) {
1241 const unsigned char kV2Input[] = {
1242 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1
1243 0x00, 0x00, 0x00, 0x14,
1244 0x00, 0x00, 0x00, 0x01,
1245 0x00, 0x00, 0x00, 0x00,
1246 0x00, 0x00, 0x00, 0x01,
1247 0x00, 0x02, 'h', 'h',
1248 0x00, 0x02, 'v', 'v',
1250 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1
1251 0x00, 0x00, 0x00, 0x10,
1252 0x00, 0x00, 0x00, 0x01,
1253 0x00, 0x00, 0x00, 0x01,
1254 0x00, 0x02, 'a', 'a',
1255 0x00, 0x02, 'b', 'b',
1257 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1258 0x00, 0x00, 0x00, 0x0c,
1259 0xde, 0xad, 0xbe, 0xef,
1260 0xde, 0xad, 0xbe, 0xef,
1261 0xde, 0xad, 0xbe, 0xef,
1263 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF
1264 0x01, 0x00, 0x00, 0x04,
1265 0xde, 0xad, 0xbe, 0xef,
1267 const unsigned char kV3Input[] = {
1268 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1
1269 0x00, 0x00, 0x00, 0x1a,
1270 0x00, 0x00, 0x00, 0x01,
1271 0x00, 0x00, 0x00, 0x00,
1272 0x00, 0x00, 0x00, 0x00,
1273 0x00, 0x01, 0x00, 0x00,
1274 0x00, 0x02, 'h', 'h',
1275 0x00, 0x00, 0x00, 0x02,
1276 'v', 'v',
1278 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1
1279 0x00, 0x00, 0x00, 0x14,
1280 0x00, 0x00, 0x00, 0x01,
1281 0x00, 0x00, 0x00, 0x01,
1282 0x00, 0x00, 0x00, 0x02,
1283 'a', 'a', 0x00, 0x00,
1284 0x00, 0x02, 'b', 'b',
1286 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1287 0x00, 0x00, 0x00, 0x0c,
1288 0xde, 0xad, 0xbe, 0xef,
1289 0xde, 0xad, 0xbe, 0xef,
1290 0xde, 0xad, 0xbe, 0xef,
1292 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF
1293 0x01, 0x00, 0x00, 0x04,
1294 0xde, 0xad, 0xbe, 0xef,
1296 const unsigned char kV4Input[] = {
1297 0x00, 0x1e, 0x01, 0x00, // SYN_STREAM #1
1298 0x00, 0x00, 0x00, 0x01,
1299 0x00, 0x00, 0x00, 0x00,
1300 0x00, 0x00, 0x00, 0x00,
1301 0x00, 0x01, 0x00, 0x00,
1302 0x00, 0x02, 'h', 'h',
1303 0x00, 0x00, 0x00, 0x02,
1304 'v', 'v',
1306 0x00, 0x18, 0x02, 0x00, // SYN REPLY Stream #1
1307 0x00, 0x00, 0x00, 0x01,
1308 0x00, 0x00, 0x00, 0x01,
1309 0x00, 0x00, 0x00, 0x02,
1310 'a', 'a', 0x00, 0x00,
1311 0x00, 0x02, 'b', 'b',
1313 0x00, 0x14, 0x00, 0x00, // DATA on Stream #1
1314 0x00, 0x00, 0x00, 0x01,
1315 0xde, 0xad, 0xbe, 0xef,
1316 0xde, 0xad, 0xbe, 0xef,
1317 0xde, 0xad, 0xbe, 0xef,
1319 0x00, 0x0c, 0x00, 0x01, // DATA on Stream #1, with FIN
1320 0x00, 0x00, 0x00, 0x01,
1321 0xde, 0xad, 0xbe, 0xef,
1324 TestSpdyVisitor visitor(spdy_version_);
1325 if (IsSpdy2()) {
1326 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
1327 } else if (IsSpdy3()) {
1328 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
1329 } else {
1330 visitor.SimulateInFramer(kV4Input, sizeof(kV4Input));
1333 EXPECT_EQ(0, visitor.error_count_);
1334 EXPECT_EQ(1, visitor.syn_frame_count_);
1335 EXPECT_EQ(1, visitor.syn_reply_frame_count_);
1336 EXPECT_EQ(0, visitor.headers_frame_count_);
1337 EXPECT_EQ(16, visitor.data_bytes_);
1338 EXPECT_EQ(0, visitor.fin_frame_count_);
1339 EXPECT_EQ(0, visitor.fin_flag_count_);
1340 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1341 EXPECT_EQ(2, visitor.data_frame_count_);
1344 // Test that the FIN flag on a SYN reply frame signifies EOF.
1345 TEST_P(SpdyFramerTest, FinOnSynReplyFrame) {
1346 const unsigned char kV2Input[] = {
1347 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1
1348 0x00, 0x00, 0x00, 0x14,
1349 0x00, 0x00, 0x00, 0x01,
1350 0x00, 0x00, 0x00, 0x00,
1351 0x00, 0x00, 0x00, 0x01,
1352 0x00, 0x02, 'h', 'h',
1353 0x00, 0x02, 'v', 'v',
1355 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1
1356 0x01, 0x00, 0x00, 0x10,
1357 0x00, 0x00, 0x00, 0x01,
1358 0x00, 0x00, 0x00, 0x01,
1359 0x00, 0x02, 'a', 'a',
1360 0x00, 0x02, 'b', 'b',
1362 const unsigned char kV3Input[] = {
1363 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1
1364 0x00, 0x00, 0x00, 0x1a,
1365 0x00, 0x00, 0x00, 0x01,
1366 0x00, 0x00, 0x00, 0x00,
1367 0x00, 0x00, 0x00, 0x00,
1368 0x00, 0x01, 0x00, 0x00,
1369 0x00, 0x02, 'h', 'h',
1370 0x00, 0x00, 0x00, 0x02,
1371 'v', 'v',
1373 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1
1374 0x01, 0x00, 0x00, 0x14,
1375 0x00, 0x00, 0x00, 0x01,
1376 0x00, 0x00, 0x00, 0x01,
1377 0x00, 0x00, 0x00, 0x02,
1378 'a', 'a', 0x00, 0x00,
1379 0x00, 0x02, 'b', 'b',
1381 const unsigned char kV4Input[] = {
1382 0x00, 0x1e, 0x01, 0x00, // SYN_STREAM #1
1383 0x00, 0x00, 0x00, 0x01,
1384 0x00, 0x00, 0x00, 0x00,
1385 0x00, 0x00, 0x00, 0x00,
1386 0x00, 0x01, 0x00, 0x00,
1387 0x00, 0x02, 'h', 'h',
1388 0x00, 0x00, 0x00, 0x02,
1389 'v', 'v',
1391 0x00, 0x18, 0x02, 0x01, // SYN_REPLY #1, with FIN
1392 0x00, 0x00, 0x00, 0x01,
1393 0x00, 0x00, 0x00, 0x01,
1394 0x00, 0x00, 0x00, 0x02,
1395 'a', 'a', 0x00, 0x00,
1396 0x00, 0x02, 'b', 'b',
1399 TestSpdyVisitor visitor(spdy_version_);
1400 if (IsSpdy2()) {
1401 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
1402 } else if (IsSpdy3()) {
1403 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
1404 } else {
1405 visitor.SimulateInFramer(kV4Input, sizeof(kV4Input));
1408 EXPECT_EQ(0, visitor.error_count_);
1409 EXPECT_EQ(1, visitor.syn_frame_count_);
1410 EXPECT_EQ(1, visitor.syn_reply_frame_count_);
1411 EXPECT_EQ(0, visitor.headers_frame_count_);
1412 EXPECT_EQ(0, visitor.data_bytes_);
1413 EXPECT_EQ(0, visitor.fin_frame_count_);
1414 EXPECT_EQ(1, visitor.fin_flag_count_);
1415 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1416 EXPECT_EQ(0, visitor.data_frame_count_);
1419 TEST_P(SpdyFramerTest, HeaderCompression) {
1420 SpdyFramer send_framer(spdy_version_);
1421 SpdyFramer recv_framer(spdy_version_);
1423 send_framer.set_enable_compression(true);
1424 recv_framer.set_enable_compression(true);
1426 const char kHeader1[] = "header1";
1427 const char kHeader2[] = "header2";
1428 const char kHeader3[] = "header3";
1429 const char kValue1[] = "value1";
1430 const char kValue2[] = "value2";
1431 const char kValue3[] = "value3";
1433 // SYN_STREAM #1
1434 SpdyHeaderBlock block;
1435 block[kHeader1] = kValue1;
1436 block[kHeader2] = kValue2;
1437 SpdyControlFlags flags(CONTROL_FLAG_NONE);
1438 SpdySynStreamIR syn_ir_1(1);
1439 syn_ir_1.SetHeader(kHeader1, kValue1);
1440 syn_ir_1.SetHeader(kHeader2, kValue2);
1441 scoped_ptr<SpdyFrame> syn_frame_1(send_framer.SerializeSynStream(syn_ir_1));
1442 EXPECT_TRUE(syn_frame_1.get() != NULL);
1444 // SYN_STREAM #2
1445 block[kHeader3] = kValue3;
1446 scoped_ptr<SpdyFrame> syn_frame_2(
1447 send_framer.CreateSynStream(3, // stream id
1448 0, // associated stream id
1449 0, // priority
1450 0, // credential slot
1451 flags,
1452 true, // compress
1453 &block));
1454 EXPECT_TRUE(syn_frame_2.get() != NULL);
1456 // Now start decompressing
1457 scoped_ptr<SpdyFrame> decompressed;
1458 scoped_ptr<SpdyFrame> uncompressed;
1459 base::StringPiece serialized_headers;
1460 SpdyHeaderBlock decompressed_headers;
1462 // Decompress SYN_STREAM #1
1463 decompressed.reset(SpdyFramerTestUtil::DecompressFrame(
1464 &recv_framer, *syn_frame_1.get()));
1465 EXPECT_TRUE(decompressed.get() != NULL);
1466 serialized_headers = GetSerializedHeaders(decompressed.get(), send_framer);
1467 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
1468 serialized_headers.size(),
1469 &decompressed_headers));
1470 EXPECT_EQ(2u, decompressed_headers.size());
1471 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
1472 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
1474 // Decompress SYN_STREAM #2
1475 decompressed.reset(SpdyFramerTestUtil::DecompressFrame(
1476 &recv_framer, *syn_frame_2.get()));
1477 EXPECT_TRUE(decompressed.get() != NULL);
1478 serialized_headers = GetSerializedHeaders(decompressed.get(), send_framer);
1479 decompressed_headers.clear();
1480 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
1481 serialized_headers.size(),
1482 &decompressed_headers));
1483 EXPECT_EQ(3u, decompressed_headers.size());
1484 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
1485 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
1486 EXPECT_EQ(kValue3, decompressed_headers[kHeader3]);
1489 // Verify we don't leak when we leave streams unclosed
1490 TEST_P(SpdyFramerTest, UnclosedStreamDataCompressors) {
1491 SpdyFramer send_framer(spdy_version_);
1493 send_framer.set_enable_compression(true);
1495 const char kHeader1[] = "header1";
1496 const char kHeader2[] = "header2";
1497 const char kValue1[] = "value1";
1498 const char kValue2[] = "value2";
1500 SpdyHeaderBlock block;
1501 block[kHeader1] = kValue1;
1502 block[kHeader2] = kValue2;
1503 SpdyControlFlags flags(CONTROL_FLAG_NONE);
1504 scoped_ptr<SpdyFrame> syn_frame(
1505 send_framer.CreateSynStream(1, // stream id
1506 0, // associated stream id
1507 0, // priority
1508 0, // credential slot
1509 flags,
1510 true, // compress
1511 &block));
1512 EXPECT_TRUE(syn_frame.get() != NULL);
1514 const char bytes[] = "this is a test test test test test!";
1515 scoped_ptr<SpdyFrame> send_frame(
1516 send_framer.CreateDataFrame(
1517 1, bytes, arraysize(bytes),
1518 static_cast<SpdyDataFlags>(DATA_FLAG_FIN)));
1519 EXPECT_TRUE(send_frame.get() != NULL);
1521 // Run the inputs through the framer.
1522 TestSpdyVisitor visitor(spdy_version_);
1523 visitor.use_compression_ = true;
1524 const unsigned char* data;
1525 data = reinterpret_cast<const unsigned char*>(syn_frame->data());
1526 visitor.SimulateInFramer(data, syn_frame->size());
1527 data = reinterpret_cast<const unsigned char*>(send_frame->data());
1528 visitor.SimulateInFramer(data, send_frame->size());
1530 EXPECT_EQ(0, visitor.error_count_);
1531 EXPECT_EQ(1, visitor.syn_frame_count_);
1532 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1533 EXPECT_EQ(0, visitor.headers_frame_count_);
1534 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_));
1535 EXPECT_EQ(0, visitor.fin_frame_count_);
1536 EXPECT_EQ(0, visitor.fin_flag_count_);
1537 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1538 EXPECT_EQ(1, visitor.data_frame_count_);
1541 // Verify we can decompress the stream even if handed over to the
1542 // framer 1 byte at a time.
1543 TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) {
1544 SpdyFramer send_framer(spdy_version_);
1546 send_framer.set_enable_compression(true);
1548 const char kHeader1[] = "header1";
1549 const char kHeader2[] = "header2";
1550 const char kValue1[] = "value1";
1551 const char kValue2[] = "value2";
1553 SpdyHeaderBlock block;
1554 block[kHeader1] = kValue1;
1555 block[kHeader2] = kValue2;
1556 SpdyControlFlags flags(CONTROL_FLAG_NONE);
1557 scoped_ptr<SpdyFrame> syn_frame(
1558 send_framer.CreateSynStream(1, // stream id
1559 0, // associated stream id
1560 0, // priority
1561 0, // credential slot
1562 flags,
1563 true, // compress
1564 &block));
1565 EXPECT_TRUE(syn_frame.get() != NULL);
1567 const char bytes[] = "this is a test test test test test!";
1568 scoped_ptr<SpdyFrame> send_frame(
1569 send_framer.CreateDataFrame(
1570 1, bytes, arraysize(bytes),
1571 static_cast<SpdyDataFlags>(DATA_FLAG_FIN)));
1572 EXPECT_TRUE(send_frame.get() != NULL);
1574 // Run the inputs through the framer.
1575 TestSpdyVisitor visitor(spdy_version_);
1576 visitor.use_compression_ = true;
1577 const unsigned char* data;
1578 data = reinterpret_cast<const unsigned char*>(syn_frame->data());
1579 for (size_t idx = 0; idx < syn_frame->size(); ++idx) {
1580 visitor.SimulateInFramer(data + idx, 1);
1581 ASSERT_EQ(0, visitor.error_count_);
1583 data = reinterpret_cast<const unsigned char*>(send_frame->data());
1584 for (size_t idx = 0; idx < send_frame->size(); ++idx) {
1585 visitor.SimulateInFramer(data + idx, 1);
1586 ASSERT_EQ(0, visitor.error_count_);
1589 EXPECT_EQ(0, visitor.error_count_);
1590 EXPECT_EQ(1, visitor.syn_frame_count_);
1591 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1592 EXPECT_EQ(0, visitor.headers_frame_count_);
1593 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_));
1594 EXPECT_EQ(0, visitor.fin_frame_count_);
1595 EXPECT_EQ(0, visitor.fin_flag_count_);
1596 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1597 EXPECT_EQ(1, visitor.data_frame_count_);
1600 TEST_P(SpdyFramerTest, WindowUpdateFrame) {
1601 SpdyFramer framer(spdy_version_);
1602 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x12345678));
1604 const char kDescription[] = "WINDOW_UPDATE frame, stream 1, delta 0x12345678";
1605 const unsigned char kV3FrameData[] = { // Also applies for V2.
1606 0x80, spdy_version_ch_, 0x00, 0x09,
1607 0x00, 0x00, 0x00, 0x08,
1608 0x00, 0x00, 0x00, 0x01,
1609 0x12, 0x34, 0x56, 0x78
1611 const unsigned char kV4FrameData[] = {
1612 0x00, 0x0c, 0x09, 0x00,
1613 0x00, 0x00, 0x00, 0x01,
1614 0x12, 0x34, 0x56, 0x78
1617 if (IsSpdy4()) {
1618 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1619 } else {
1620 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1624 TEST_P(SpdyFramerTest, CreateDataFrame) {
1625 SpdyFramer framer(spdy_version_);
1628 const char kDescription[] = "'hello' data frame, no FIN";
1629 const unsigned char kV3FrameData[] = { // Also applies for V2.
1630 0x00, 0x00, 0x00, 0x01,
1631 0x00, 0x00, 0x00, 0x05,
1632 'h', 'e', 'l', 'l',
1635 const unsigned char kV4FrameData[] = {
1636 0x00, 0x0d, 0x00, 0x00,
1637 0x00, 0x00, 0x00, 0x01,
1638 'h', 'e', 'l', 'l',
1641 const char bytes[] = "hello";
1643 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1644 1, bytes, strlen(bytes), DATA_FLAG_NONE));
1645 if (IsSpdy4()) {
1646 CompareFrame(
1647 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1648 } else {
1649 CompareFrame(
1650 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1653 SpdyDataIR data_ir(1);
1654 data_ir.SetDataShallow(base::StringPiece(bytes, strlen(bytes)));
1655 frame.reset(framer.SerializeDataFrameHeader(data_ir));
1656 CompareCharArraysWithHexError(
1657 kDescription,
1658 reinterpret_cast<const unsigned char*>(frame->data()),
1659 framer.GetDataFrameMinimumSize(),
1660 IsSpdy4() ? kV4FrameData : kV3FrameData,
1661 framer.GetDataFrameMinimumSize());
1665 const char kDescription[] = "Data frame with negative data byte, no FIN";
1666 const unsigned char kV3FrameData[] = { // Also applies for V2.
1667 0x00, 0x00, 0x00, 0x01,
1668 0x00, 0x00, 0x00, 0x01,
1669 0xff
1671 const unsigned char kV4FrameData[] = {
1672 0x00, 0x09, 0x00, 0x00,
1673 0x00, 0x00, 0x00, 0x01,
1674 0xff
1676 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1677 1, "\xff", 1, DATA_FLAG_NONE));
1678 if (IsSpdy4()) {
1679 CompareFrame(
1680 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1681 } else {
1682 CompareFrame(
1683 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1688 const char kDescription[] = "'hello' data frame, with FIN";
1689 const unsigned char kV3FrameData[] = { // Also applies for V2.
1690 0x00, 0x00, 0x00, 0x01,
1691 0x01, 0x00, 0x00, 0x05,
1692 'h', 'e', 'l', 'l',
1695 const unsigned char kV4FrameData[] = {
1696 0x00, 0x0d, 0x00, 0x01,
1697 0x00, 0x00, 0x00, 0x01,
1698 'h', 'e', 'l', 'l',
1701 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1702 1, "hello", 5, DATA_FLAG_FIN));
1703 if (IsSpdy4()) {
1704 CompareFrame(
1705 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1706 } else {
1707 CompareFrame(
1708 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1713 const char kDescription[] = "Empty data frame";
1714 const unsigned char kV3FrameData[] = { // Also applies for V2.
1715 0x00, 0x00, 0x00, 0x01,
1716 0x00, 0x00, 0x00, 0x00,
1718 const unsigned char kV4FrameData[] = {
1719 0x00, 0x08, 0x00, 0x00,
1720 0x00, 0x00, 0x00, 0x01,
1722 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1723 1, "", 0, DATA_FLAG_NONE));
1724 if (IsSpdy4()) {
1725 CompareFrame(
1726 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1727 } else {
1728 CompareFrame(
1729 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1734 const char kDescription[] = "Data frame with max stream ID";
1735 const unsigned char kV3FrameData[] = { // Also applies for V2.
1736 0x7f, 0xff, 0xff, 0xff,
1737 0x01, 0x00, 0x00, 0x05,
1738 'h', 'e', 'l', 'l',
1741 const unsigned char kV4FrameData[] = {
1742 0x00, 0x0d, 0x00, 0x01,
1743 0x7f, 0xff, 0xff, 0xff,
1744 'h', 'e', 'l', 'l',
1747 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1748 0x7fffffff, "hello", 5, DATA_FLAG_FIN));
1749 if (IsSpdy4()) {
1750 CompareFrame(
1751 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1752 } else {
1753 CompareFrame(
1754 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1758 if (!IsSpdy4()) {
1759 // This test does not apply to SPDY 4 because the max frame size is smaller
1760 // than 4MB.
1761 const char kDescription[] = "Large data frame";
1762 const int kDataSize = 4 * 1024 * 1024; // 4 MB
1763 const string kData(kDataSize, 'A');
1764 const unsigned char kFrameHeader[] = {
1765 0x00, 0x00, 0x00, 0x01,
1766 0x01, 0x40, 0x00, 0x00,
1769 const int kFrameSize = arraysize(kFrameHeader) + kDataSize;
1770 scoped_ptr<unsigned char[]> expected_frame_data(
1771 new unsigned char[kFrameSize]);
1772 memcpy(expected_frame_data.get(), kFrameHeader, arraysize(kFrameHeader));
1773 memset(expected_frame_data.get() + arraysize(kFrameHeader), 'A', kDataSize);
1775 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1776 1, kData.data(), kData.size(), DATA_FLAG_FIN));
1777 CompareFrame(kDescription, *frame, expected_frame_data.get(), kFrameSize);
1781 TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
1782 SpdyFramer framer(spdy_version_);
1783 framer.set_enable_compression(false);
1786 const char kDescription[] = "SYN_STREAM frame, lowest pri, slot 2, no FIN";
1788 SpdyHeaderBlock headers;
1789 headers["bar"] = "foo";
1790 headers["foo"] = "bar";
1792 const unsigned char kPri = IsSpdy2() ? 0xC0 : 0xE0;
1793 const unsigned char kCre = IsSpdy2() ? 0 : 2;
1794 const unsigned char kV2FrameData[] = {
1795 0x80, spdy_version_ch_, 0x00, 0x01,
1796 0x00, 0x00, 0x00, 0x20,
1797 0x00, 0x00, 0x00, 0x01,
1798 0x00, 0x00, 0x00, 0x00,
1799 kPri, 0x00, 0x00, 0x02,
1800 0x00, 0x03, 'b', 'a',
1801 'r', 0x00, 0x03, 'f',
1802 'o', 'o', 0x00, 0x03,
1803 'f', 'o', 'o', 0x00,
1804 0x03, 'b', 'a', 'r'
1806 const unsigned char kV3FrameData[] = {
1807 0x80, spdy_version_ch_, 0x00, 0x01,
1808 0x00, 0x00, 0x00, 0x2a,
1809 0x00, 0x00, 0x00, 0x01,
1810 0x00, 0x00, 0x00, 0x00,
1811 kPri, kCre, 0x00, 0x00,
1812 0x00, 0x02, 0x00, 0x00,
1813 0x00, 0x03, 'b', 'a',
1814 'r', 0x00, 0x00, 0x00,
1815 0x03, 'f', 'o', 'o',
1816 0x00, 0x00, 0x00, 0x03,
1817 'f', 'o', 'o', 0x00,
1818 0x00, 0x00, 0x03, 'b',
1819 'a', 'r'
1821 const unsigned char kV4FrameData[] = {
1822 0x00, 0x2e, 0x01, 0x00,
1823 0x00, 0x00, 0x00, 0x01,
1824 0x00, 0x00, 0x00, 0x00,
1825 kPri, kCre, 0x00, 0x00,
1826 0x00, 0x02, 0x00, 0x00,
1827 0x00, 0x03, 'b', 'a',
1828 'r', 0x00, 0x00, 0x00,
1829 0x03, 'f', 'o', 'o',
1830 0x00, 0x00, 0x00, 0x03,
1831 'f', 'o', 'o', 0x00,
1832 0x00, 0x00, 0x03, 'b',
1833 'a', 'r'
1835 scoped_ptr<SpdyFrame> frame(
1836 framer.CreateSynStream(1, // stream id
1837 0, // associated stream id
1838 framer.GetLowestPriority(),
1839 kCre, // credential slot
1840 CONTROL_FLAG_NONE,
1841 false, // compress
1842 &headers));
1843 if (IsSpdy2()) {
1844 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
1845 } else if (IsSpdy3()) {
1846 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1847 } else {
1848 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1853 const char kDescription[] =
1854 "SYN_STREAM frame with a 0-length header name, highest pri, FIN, "
1855 "max stream ID";
1857 SpdyHeaderBlock headers;
1858 headers[std::string()] = "foo";
1859 headers["foo"] = "bar";
1861 const unsigned char kV2FrameData[] = {
1862 0x80, spdy_version_ch_, 0x00, 0x01,
1863 0x01, 0x00, 0x00, 0x1D,
1864 0x7f, 0xff, 0xff, 0xff,
1865 0x7f, 0xff, 0xff, 0xff,
1866 0x00, 0x00, 0x00, 0x02,
1867 0x00, 0x00, 0x00, 0x03,
1868 'f', 'o', 'o', 0x00,
1869 0x03, 'f', 'o', 'o',
1870 0x00, 0x03, 'b', 'a',
1873 const unsigned char kV3FrameData[] = {
1874 0x80, spdy_version_ch_, 0x00, 0x01,
1875 0x01, 0x00, 0x00, 0x27,
1876 0x7f, 0xff, 0xff, 0xff,
1877 0x7f, 0xff, 0xff, 0xff,
1878 0x00, 0x00, 0x00, 0x00,
1879 0x00, 0x02, 0x00, 0x00,
1880 0x00, 0x00, 0x00, 0x00,
1881 0x00, 0x03, 'f', 'o',
1882 'o', 0x00, 0x00, 0x00,
1883 0x03, 'f', 'o', 'o',
1884 0x00, 0x00, 0x00, 0x03,
1885 'b', 'a', 'r'
1887 const unsigned char kV4FrameData[] = {
1888 0x00, 0x2b, 0x01, 0x01,
1889 0x7f, 0xff, 0xff, 0xff,
1890 0x7f, 0xff, 0xff, 0xff,
1891 0x00, 0x00, 0x00, 0x00,
1892 0x00, 0x02, 0x00, 0x00,
1893 0x00, 0x00, 0x00, 0x00,
1894 0x00, 0x03, 'f', 'o',
1895 'o', 0x00, 0x00, 0x00,
1896 0x03, 'f', 'o', 'o',
1897 0x00, 0x00, 0x00, 0x03,
1898 'b', 'a', 'r'
1900 scoped_ptr<SpdyFrame> frame(
1901 framer.CreateSynStream(0x7fffffff, // stream id
1902 0x7fffffff, // associated stream id
1903 framer.GetHighestPriority(),
1904 0, // credential slot
1905 CONTROL_FLAG_FIN,
1906 false, // compress
1907 &headers));
1908 if (IsSpdy2()) {
1909 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
1910 } else if (IsSpdy3()) {
1911 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1912 } else {
1913 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1918 const char kDescription[] =
1919 "SYN_STREAM frame with a 0-length header val, high pri, FIN, "
1920 "max stream ID";
1922 SpdyHeaderBlock headers;
1923 headers["bar"] = "foo";
1924 headers["foo"] = "";
1926 const unsigned char kPri = IsSpdy2() ? 0x40 : 0x20;
1927 const unsigned char kV2FrameData[] = {
1928 0x80, spdy_version_ch_, 0x00, 0x01,
1929 0x01, 0x00, 0x00, 0x1D,
1930 0x7f, 0xff, 0xff, 0xff,
1931 0x7f, 0xff, 0xff, 0xff,
1932 kPri, 0x00, 0x00, 0x02,
1933 0x00, 0x03, 'b', 'a',
1934 'r', 0x00, 0x03, 'f',
1935 'o', 'o', 0x00, 0x03,
1936 'f', 'o', 'o', 0x00,
1937 0x00
1939 const unsigned char kV3FrameData[] = {
1940 0x80, spdy_version_ch_, 0x00, 0x01,
1941 0x01, 0x00, 0x00, 0x27,
1942 0x7f, 0xff, 0xff, 0xff,
1943 0x7f, 0xff, 0xff, 0xff,
1944 kPri, 0x00, 0x00, 0x00,
1945 0x00, 0x02, 0x00, 0x00,
1946 0x00, 0x03, 'b', 'a',
1947 'r', 0x00, 0x00, 0x00,
1948 0x03, 'f', 'o', 'o',
1949 0x00, 0x00, 0x00, 0x03,
1950 'f', 'o', 'o', 0x00,
1951 0x00, 0x00, 0x00
1953 const unsigned char kV4FrameData[] = {
1954 0x00, 0x2b, 0x01, 0x01,
1955 0x7f, 0xff, 0xff, 0xff,
1956 0x7f, 0xff, 0xff, 0xff,
1957 kPri, 0x00, 0x00, 0x00,
1958 0x00, 0x02, 0x00, 0x00,
1959 0x00, 0x03, 'b', 'a',
1960 'r', 0x00, 0x00, 0x00,
1961 0x03, 'f', 'o', 'o',
1962 0x00, 0x00, 0x00, 0x03,
1963 'f', 'o', 'o', 0x00,
1964 0x00, 0x00, 0x00
1966 scoped_ptr<SpdyFrame> frame(
1967 framer.CreateSynStream(0x7fffffff, // stream id
1968 0x7fffffff, // associated stream id
1969 1, // priority
1970 0, // credential slot
1971 CONTROL_FLAG_FIN,
1972 false, // compress
1973 &headers));
1974 if (IsSpdy2()) {
1975 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
1976 } else if (IsSpdy3()) {
1977 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1978 } else {
1979 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1984 // TODO(phajdan.jr): Clean up after we no longer need
1985 // to workaround http://crbug.com/139744.
1986 #if !defined(USE_SYSTEM_ZLIB)
1987 TEST_P(SpdyFramerTest, CreateSynStreamCompressed) {
1988 SpdyFramer framer(spdy_version_);
1989 framer.set_enable_compression(true);
1992 const char kDescription[] =
1993 "SYN_STREAM frame, low pri, no FIN";
1995 SpdyHeaderBlock headers;
1996 headers["bar"] = "foo";
1997 headers["foo"] = "bar";
1999 const SpdyPriority priority = IsSpdy2() ? 2 : 4;
2000 const unsigned char kV2FrameData[] = {
2001 0x80, spdy_version_ch_, 0x00, 0x01,
2002 0x00, 0x00, 0x00, 0x36,
2003 0x00, 0x00, 0x00, 0x01,
2004 0x00, 0x00, 0x00, 0x00,
2005 0x80, 0x00, 0x38, 0xea,
2006 0xdf, 0xa2, 0x51, 0xb2,
2007 0x62, 0x60, 0x62, 0x60,
2008 0x4e, 0x4a, 0x2c, 0x62,
2009 0x60, 0x06, 0x08, 0xa0,
2010 0xb4, 0xfc, 0x7c, 0x80,
2011 0x00, 0x62, 0x60, 0x4e,
2012 0xcb, 0xcf, 0x67, 0x60,
2013 0x06, 0x08, 0xa0, 0xa4,
2014 0xc4, 0x22, 0x80, 0x00,
2015 0x02, 0x00, 0x00, 0x00,
2016 0xff, 0xff,
2018 const unsigned char kV3FrameData[] = {
2019 0x80, spdy_version_ch_, 0x00, 0x01,
2020 0x00, 0x00, 0x00, 0x37,
2021 0x00, 0x00, 0x00, 0x01,
2022 0x00, 0x00, 0x00, 0x00,
2023 0x80, 0x00, 0x38, 0xEA,
2024 0xE3, 0xC6, 0xA7, 0xC2,
2025 0x02, 0xE5, 0x0E, 0x50,
2026 0xC2, 0x4B, 0x4A, 0x04,
2027 0xE5, 0x0B, 0x66, 0x80,
2028 0x00, 0x4A, 0xCB, 0xCF,
2029 0x07, 0x08, 0x20, 0x10,
2030 0x95, 0x96, 0x9F, 0x0F,
2031 0xA2, 0x00, 0x02, 0x28,
2032 0x29, 0xB1, 0x08, 0x20,
2033 0x80, 0x00, 0x00, 0x00,
2034 0x00, 0xFF, 0xFF,
2036 const unsigned char kV4FrameData[] = {
2037 0x00, 0x3b, 0x01, 0x00,
2038 0x00, 0x00, 0x00, 0x01,
2039 0x00, 0x00, 0x00, 0x00,
2040 0x80, 0x00, 0x38, 0xea,
2041 0xe3, 0xc6, 0xa7, 0xc2,
2042 0x02, 0xe5, 0x0e, 0x50,
2043 0xc2, 0x4b, 0x4a, 0x04,
2044 0xe5, 0x0b, 0x66, 0x80,
2045 0x00, 0x4a, 0xcb, 0xcf,
2046 0x07, 0x08, 0x20, 0x10,
2047 0x95, 0x96, 0x9f, 0x0f,
2048 0xa2, 0x00, 0x02, 0x28,
2049 0x29, 0xb1, 0x08, 0x20,
2050 0x80, 0x00, 0x00, 0x00,
2051 0x00, 0xff, 0xff,
2053 scoped_ptr<SpdyFrame> frame(
2054 framer.CreateSynStream(1, // stream id
2055 0, // associated stream id
2056 priority,
2057 0, // credential slot
2058 CONTROL_FLAG_NONE,
2059 true, // compress
2060 &headers));
2061 if (IsSpdy2()) {
2062 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2063 } else if (IsSpdy3()) {
2064 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2065 } else {
2066 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2070 #endif // !defined(USE_SYSTEM_ZLIB)
2072 TEST_P(SpdyFramerTest, CreateSynReplyUncompressed) {
2073 SpdyFramer framer(spdy_version_);
2074 framer.set_enable_compression(false);
2077 const char kDescription[] = "SYN_REPLY frame, no FIN";
2079 SpdyHeaderBlock headers;
2080 headers["bar"] = "foo";
2081 headers["foo"] = "bar";
2083 const unsigned char kV2FrameData[] = {
2084 0x80, spdy_version_ch_, 0x00, 0x02,
2085 0x00, 0x00, 0x00, 0x1C,
2086 0x00, 0x00, 0x00, 0x01,
2087 0x00, 0x00, 0x00, 0x02,
2088 0x00, 0x03, 'b', 'a',
2089 'r', 0x00, 0x03, 'f',
2090 'o', 'o', 0x00, 0x03,
2091 'f', 'o', 'o', 0x00,
2092 0x03, 'b', 'a', 'r'
2094 const unsigned char kV3FrameData[] = {
2095 0x80, spdy_version_ch_, 0x00, 0x02,
2096 0x00, 0x00, 0x00, 0x24,
2097 0x00, 0x00, 0x00, 0x01,
2098 0x00, 0x00, 0x00, 0x02,
2099 0x00, 0x00, 0x00, 0x03,
2100 'b', 'a', 'r', 0x00,
2101 0x00, 0x00, 0x03, 'f',
2102 'o', 'o', 0x00, 0x00,
2103 0x00, 0x03, 'f', 'o',
2104 'o', 0x00, 0x00, 0x00,
2105 0x03, 'b', 'a', 'r'
2107 const unsigned char kV4FrameData[] = {
2108 0x00, 0x28, 0x02, 0x00,
2109 0x00, 0x00, 0x00, 0x01,
2110 0x00, 0x00, 0x00, 0x02,
2111 0x00, 0x00, 0x00, 0x03,
2112 'b', 'a', 'r', 0x00,
2113 0x00, 0x00, 0x03, 'f',
2114 'o', 'o', 0x00, 0x00,
2115 0x00, 0x03, 'f', 'o',
2116 'o', 0x00, 0x00, 0x00,
2117 0x03, 'b', 'a', 'r'
2119 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
2120 1, CONTROL_FLAG_NONE, false, &headers));
2121 if (IsSpdy2()) {
2122 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2123 } else if (IsSpdy3()) {
2124 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2125 } else {
2126 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2131 const char kDescription[] =
2132 "SYN_REPLY frame with a 0-length header name, FIN, max stream ID";
2134 SpdyHeaderBlock headers;
2135 headers[std::string()] = "foo";
2136 headers["foo"] = "bar";
2138 const unsigned char kV2FrameData[] = {
2139 0x80, spdy_version_ch_, 0x00, 0x02,
2140 0x01, 0x00, 0x00, 0x19,
2141 0x7f, 0xff, 0xff, 0xff,
2142 0x00, 0x00, 0x00, 0x02,
2143 0x00, 0x00, 0x00, 0x03,
2144 'f', 'o', 'o', 0x00,
2145 0x03, 'f', 'o', 'o',
2146 0x00, 0x03, 'b', 'a',
2149 const unsigned char kV3FrameData[] = {
2150 0x80, spdy_version_ch_, 0x00, 0x02,
2151 0x01, 0x00, 0x00, 0x21,
2152 0x7f, 0xff, 0xff, 0xff,
2153 0x00, 0x00, 0x00, 0x02,
2154 0x00, 0x00, 0x00, 0x00,
2155 0x00, 0x00, 0x00, 0x03,
2156 'f', 'o', 'o', 0x00,
2157 0x00, 0x00, 0x03, 'f',
2158 'o', 'o', 0x00, 0x00,
2159 0x00, 0x03, 'b', 'a',
2162 const unsigned char kV4FrameData[] = {
2163 0x00, 0x25, 0x02, 0x01,
2164 0x7f, 0xff, 0xff, 0xff,
2165 0x00, 0x00, 0x00, 0x02,
2166 0x00, 0x00, 0x00, 0x00,
2167 0x00, 0x00, 0x00, 0x03,
2168 'f', 'o', 'o', 0x00,
2169 0x00, 0x00, 0x03, 'f',
2170 'o', 'o', 0x00, 0x00,
2171 0x00, 0x03, 'b', 'a',
2174 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
2175 0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
2176 if (IsSpdy2()) {
2177 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2178 } else if (IsSpdy3()) {
2179 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2180 } else {
2181 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2186 const char kDescription[] =
2187 "SYN_REPLY frame with a 0-length header val, FIN, max stream ID";
2189 SpdyHeaderBlock headers;
2190 headers["bar"] = "foo";
2191 headers["foo"] = "";
2193 const unsigned char kV2FrameData[] = {
2194 0x80, spdy_version_ch_, 0x00, 0x02,
2195 0x01, 0x00, 0x00, 0x19,
2196 0x7f, 0xff, 0xff, 0xff,
2197 0x00, 0x00, 0x00, 0x02,
2198 0x00, 0x03, 'b', 'a',
2199 'r', 0x00, 0x03, 'f',
2200 'o', 'o', 0x00, 0x03,
2201 'f', 'o', 'o', 0x00,
2202 0x00
2204 const unsigned char kV3FrameData[] = {
2205 0x80, spdy_version_ch_, 0x00, 0x02,
2206 0x01, 0x00, 0x00, 0x21,
2207 0x7f, 0xff, 0xff, 0xff,
2208 0x00, 0x00, 0x00, 0x02,
2209 0x00, 0x00, 0x00, 0x03,
2210 'b', 'a', 'r', 0x00,
2211 0x00, 0x00, 0x03, 'f',
2212 'o', 'o', 0x00, 0x00,
2213 0x00, 0x03, 'f', 'o',
2214 'o', 0x00, 0x00, 0x00,
2215 0x00
2217 const unsigned char kV4FrameData[] = {
2218 0x00, 0x25, 0x02, 0x01,
2219 0x7f, 0xff, 0xff, 0xff,
2220 0x00, 0x00, 0x00, 0x02,
2221 0x00, 0x00, 0x00, 0x03,
2222 'b', 'a', 'r', 0x00,
2223 0x00, 0x00, 0x03, 'f',
2224 'o', 'o', 0x00, 0x00,
2225 0x00, 0x03, 'f', 'o',
2226 'o', 0x00, 0x00, 0x00,
2227 0x00
2229 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
2230 0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
2231 if (IsSpdy2()) {
2232 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2233 } else if (IsSpdy3()) {
2234 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2235 } else {
2236 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2241 // TODO(phajdan.jr): Clean up after we no longer need
2242 // to workaround http://crbug.com/139744.
2243 #if !defined(USE_SYSTEM_ZLIB)
2244 TEST_P(SpdyFramerTest, CreateSynReplyCompressed) {
2245 SpdyFramer framer(spdy_version_);
2246 framer.set_enable_compression(true);
2249 const char kDescription[] = "SYN_REPLY frame, no FIN";
2251 SpdyHeaderBlock headers;
2252 headers["bar"] = "foo";
2253 headers["foo"] = "bar";
2255 const unsigned char kV2FrameData[] = {
2256 0x80, spdy_version_ch_, 0x00, 0x02,
2257 0x00, 0x00, 0x00, 0x32,
2258 0x00, 0x00, 0x00, 0x01,
2259 0x00, 0x00, 0x38, 0xea,
2260 0xdf, 0xa2, 0x51, 0xb2,
2261 0x62, 0x60, 0x62, 0x60,
2262 0x4e, 0x4a, 0x2c, 0x62,
2263 0x60, 0x06, 0x08, 0xa0,
2264 0xb4, 0xfc, 0x7c, 0x80,
2265 0x00, 0x62, 0x60, 0x4e,
2266 0xcb, 0xcf, 0x67, 0x60,
2267 0x06, 0x08, 0xa0, 0xa4,
2268 0xc4, 0x22, 0x80, 0x00,
2269 0x02, 0x00, 0x00, 0x00,
2270 0xff, 0xff,
2272 const unsigned char kV3FrameData[] = {
2273 0x80, spdy_version_ch_, 0x00, 0x02,
2274 0x00, 0x00, 0x00, 0x31,
2275 0x00, 0x00, 0x00, 0x01,
2276 0x38, 0xea, 0xe3, 0xc6,
2277 0xa7, 0xc2, 0x02, 0xe5,
2278 0x0e, 0x50, 0xc2, 0x4b,
2279 0x4a, 0x04, 0xe5, 0x0b,
2280 0x66, 0x80, 0x00, 0x4a,
2281 0xcb, 0xcf, 0x07, 0x08,
2282 0x20, 0x10, 0x95, 0x96,
2283 0x9f, 0x0f, 0xa2, 0x00,
2284 0x02, 0x28, 0x29, 0xb1,
2285 0x08, 0x20, 0x80, 0x00,
2286 0x00, 0x00, 0x00, 0xff,
2287 0xff,
2289 const unsigned char kV4FrameData[] = {
2290 0x00, 0x35, 0x02, 0x00,
2291 0x00, 0x00, 0x00, 0x01,
2292 0x38, 0xea, 0xe3, 0xc6,
2293 0xa7, 0xc2, 0x02, 0xe5,
2294 0x0e, 0x50, 0xc2, 0x4b,
2295 0x4a, 0x04, 0xe5, 0x0b,
2296 0x66, 0x80, 0x00, 0x4a,
2297 0xcb, 0xcf, 0x07, 0x08,
2298 0x20, 0x10, 0x95, 0x96,
2299 0x9f, 0x0f, 0xa2, 0x00,
2300 0x02, 0x28, 0x29, 0xb1,
2301 0x08, 0x20, 0x80, 0x00,
2302 0x00, 0x00, 0x00, 0xff,
2303 0xff,
2305 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
2306 1, CONTROL_FLAG_NONE, true, &headers));
2307 if (IsSpdy2()) {
2308 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2309 } else if (IsSpdy3()) {
2310 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2311 } else {
2312 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2316 #endif // !defined(USE_SYSTEM_ZLIB)
2318 TEST_P(SpdyFramerTest, CreateRstStream) {
2319 SpdyFramer framer(spdy_version_);
2322 const char kDescription[] = "RST_STREAM frame";
2323 const unsigned char kV3FrameData[] = { // Also applies for V2.
2324 0x80, spdy_version_ch_, 0x00, 0x03,
2325 0x00, 0x00, 0x00, 0x08,
2326 0x00, 0x00, 0x00, 0x01,
2327 0x00, 0x00, 0x00, 0x01,
2329 const unsigned char kV4FrameData[] = {
2330 0x00, 0x0c, 0x03, 0x00,
2331 0x00, 0x00, 0x00, 0x01,
2332 0x00, 0x00, 0x00, 0x01,
2334 scoped_ptr<SpdyFrame> frame(
2335 framer.CreateRstStream(1, RST_STREAM_PROTOCOL_ERROR));
2336 if (IsSpdy4()) {
2337 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2338 } else {
2339 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2344 const char kDescription[] = "RST_STREAM frame with max stream ID";
2345 const unsigned char kV3FrameData[] = { // Also applies for V2.
2346 0x80, spdy_version_ch_, 0x00, 0x03,
2347 0x00, 0x00, 0x00, 0x08,
2348 0x7f, 0xff, 0xff, 0xff,
2349 0x00, 0x00, 0x00, 0x01,
2351 const unsigned char kV4FrameData[] = {
2352 0x00, 0x0c, 0x03, 0x00,
2353 0x7f, 0xff, 0xff, 0xff,
2354 0x00, 0x00, 0x00, 0x01,
2356 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(
2357 0x7FFFFFFF, RST_STREAM_PROTOCOL_ERROR));
2358 if (IsSpdy4()) {
2359 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2360 } else {
2361 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2366 const char kDescription[] = "RST_STREAM frame with max status code";
2367 const unsigned char kV3FrameData[] = { // Also applies for V2.
2368 0x80, spdy_version_ch_, 0x00, 0x03,
2369 0x00, 0x00, 0x00, 0x08,
2370 0x7f, 0xff, 0xff, 0xff,
2371 0x00, 0x00, 0x00, 0x06,
2373 const unsigned char kV4FrameData[] = {
2374 0x00, 0x0c, 0x03, 0x00,
2375 0x7f, 0xff, 0xff, 0xff,
2376 0x00, 0x00, 0x00, 0x06,
2378 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(
2379 0x7FFFFFFF, RST_STREAM_INTERNAL_ERROR));
2380 if (IsSpdy4()) {
2381 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2382 } else {
2383 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2388 TEST_P(SpdyFramerTest, CreateSettings) {
2389 SpdyFramer framer(spdy_version_);
2392 const char kDescription[] = "Network byte order SETTINGS frame";
2394 uint32 kValue = 0x0a0b0c0d;
2395 SpdySettingsFlags kFlags = static_cast<SpdySettingsFlags>(0x01);
2396 SpdySettingsIds kId = static_cast<SpdySettingsIds>(0x020304);
2398 SettingsMap settings;
2399 settings[kId] = SettingsFlagsAndValue(kFlags, kValue);
2401 EXPECT_EQ(kFlags, settings[kId].first);
2402 EXPECT_EQ(kValue, settings[kId].second);
2404 const unsigned char kV2FrameData[] = {
2405 0x80, spdy_version_ch_, 0x00, 0x04,
2406 0x00, 0x00, 0x00, 0x0c,
2407 0x00, 0x00, 0x00, 0x01,
2408 0x04, 0x03, 0x02, 0x01,
2409 0x0a, 0x0b, 0x0c, 0x0d,
2411 const unsigned char kV3FrameData[] = {
2412 0x80, spdy_version_ch_, 0x00, 0x04,
2413 0x00, 0x00, 0x00, 0x0c,
2414 0x00, 0x00, 0x00, 0x01,
2415 0x01, 0x02, 0x03, 0x04,
2416 0x0a, 0x0b, 0x0c, 0x0d,
2418 const unsigned char kV4FrameData[] = {
2419 0x00, 0x14, 0x04, 0x00,
2420 0x00, 0x00, 0x00, 0x00,
2421 0x00, 0x00, 0x00, 0x01,
2422 0x01, 0x02, 0x03, 0x04,
2423 0x0a, 0x0b, 0x0c, 0x0d,
2426 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
2427 if (IsSpdy2()) {
2428 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2429 } else if (IsSpdy3()) {
2430 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2431 } else {
2432 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2437 const char kDescription[] = "Basic SETTINGS frame";
2439 SettingsMap settings;
2440 AddSpdySettingFromWireFormat(
2441 &settings, 0x00000000, 0x00000001); // 1st Setting
2442 AddSpdySettingFromWireFormat(
2443 &settings, 0x01000001, 0x00000002); // 2nd Setting
2444 AddSpdySettingFromWireFormat(
2445 &settings, 0x02000002, 0x00000003); // 3rd Setting
2446 AddSpdySettingFromWireFormat(
2447 &settings, 0x03000003, 0xff000004); // 4th Setting
2449 const unsigned char kV3FrameData[] = { // Also applies for V2.
2450 0x80, spdy_version_ch_, 0x00, 0x04,
2451 0x00, 0x00, 0x00, 0x24,
2452 0x00, 0x00, 0x00, 0x04,
2453 0x00, 0x00, 0x00, 0x00, // 1st Setting
2454 0x00, 0x00, 0x00, 0x01,
2455 0x01, 0x00, 0x00, 0x01, // 2nd Setting
2456 0x00, 0x00, 0x00, 0x02,
2457 0x02, 0x00, 0x00, 0x02, // 3rd Setting
2458 0x00, 0x00, 0x00, 0x03,
2459 0x03, 0x00, 0x00, 0x03, // 4th Setting
2460 0xff, 0x00, 0x00, 0x04,
2462 const unsigned char kV4FrameData[] = {
2463 0x00, 0x2c, 0x04, 0x00,
2464 0x00, 0x00, 0x00, 0x00,
2465 0x00, 0x00, 0x00, 0x04,
2466 0x00, 0x00, 0x00, 0x00, // 1st Setting
2467 0x00, 0x00, 0x00, 0x01,
2468 0x01, 0x00, 0x00, 0x01, // 2nd Setting
2469 0x00, 0x00, 0x00, 0x02,
2470 0x02, 0x00, 0x00, 0x02, // 3rd Setting
2471 0x00, 0x00, 0x00, 0x03,
2472 0x03, 0x00, 0x00, 0x03, // 4th Setting
2473 0xff, 0x00, 0x00, 0x04,
2475 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
2476 if (IsSpdy4()) {
2477 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2478 } else {
2479 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2484 const char kDescription[] = "Empty SETTINGS frame";
2486 SettingsMap settings;
2488 const unsigned char kV3FrameData[] = { // Also applies for V2.
2489 0x80, spdy_version_ch_, 0x00, 0x04,
2490 0x00, 0x00, 0x00, 0x04,
2491 0x00, 0x00, 0x00, 0x00,
2493 const unsigned char kV4FrameData[] = {
2494 0x00, 0x0c, 0x04, 0x00,
2495 0x00, 0x00, 0x00, 0x00,
2496 0x00, 0x00, 0x00, 0x00,
2498 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
2499 if (IsSpdy4()) {
2500 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2501 } else {
2502 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2507 TEST_P(SpdyFramerTest, CreatePingFrame) {
2508 SpdyFramer framer(spdy_version_);
2511 const char kDescription[] = "PING frame";
2512 const unsigned char kV3FrameData[] = { // Also applies for V2.
2513 0x80, spdy_version_ch_, 0x00, 0x06,
2514 0x00, 0x00, 0x00, 0x04,
2515 0x12, 0x34, 0x56, 0x78,
2517 const unsigned char kV4FrameData[] = {
2518 0x00, 0x0c, 0x06, 0x00,
2519 0x00, 0x00, 0x00, 0x00,
2520 0x12, 0x34, 0x56, 0x78,
2522 scoped_ptr<SpdyFrame> frame(framer.CreatePingFrame(0x12345678u));
2523 if (IsSpdy4()) {
2524 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2525 } else {
2526 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2531 TEST_P(SpdyFramerTest, CreateGoAway) {
2532 SpdyFramer framer(spdy_version_);
2535 const char kDescription[] = "GOAWAY frame";
2536 const unsigned char kV2FrameData[] = {
2537 0x80, spdy_version_ch_, 0x00, 0x07,
2538 0x00, 0x00, 0x00, 0x04,
2539 0x00, 0x00, 0x00, 0x00,
2541 const unsigned char kV3FrameData[] = {
2542 0x80, spdy_version_ch_, 0x00, 0x07,
2543 0x00, 0x00, 0x00, 0x08,
2544 0x00, 0x00, 0x00, 0x00,
2545 0x00, 0x00, 0x00, 0x00,
2547 const unsigned char kV4FrameData[] = {
2548 0x00, 0x10, 0x07, 0x00,
2549 0x00, 0x00, 0x00, 0x00,
2550 0x00, 0x00, 0x00, 0x00,
2551 0x00, 0x00, 0x00, 0x00,
2553 scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0, GOAWAY_OK));
2554 if (IsSpdy2()) {
2555 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2556 } else if (IsSpdy3()) {
2557 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2558 } else {
2559 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2564 const char kDescription[] = "GOAWAY frame with max stream ID, status";
2565 const unsigned char kV2FrameData[] = {
2566 0x80, spdy_version_ch_, 0x00, 0x07,
2567 0x00, 0x00, 0x00, 0x04,
2568 0x7f, 0xff, 0xff, 0xff,
2570 const unsigned char kV3FrameData[] = {
2571 0x80, spdy_version_ch_, 0x00, 0x07,
2572 0x00, 0x00, 0x00, 0x08,
2573 0x7f, 0xff, 0xff, 0xff,
2574 0x00, 0x00, 0x00, 0x02,
2576 const unsigned char kV4FrameData[] = {
2577 0x00, 0x10, 0x07, 0x00,
2578 0x00, 0x00, 0x00, 0x00,
2579 0x7f, 0xff, 0xff, 0xff,
2580 0x00, 0x00, 0x00, 0x02,
2582 scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF,
2583 GOAWAY_INTERNAL_ERROR));
2584 if (IsSpdy2()) {
2585 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2586 } else if (IsSpdy3()) {
2587 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2588 } else {
2589 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2594 TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
2595 SpdyFramer framer(spdy_version_);
2596 framer.set_enable_compression(false);
2599 const char kDescription[] = "HEADERS frame, no FIN";
2601 SpdyHeaderBlock headers;
2602 headers["bar"] = "foo";
2603 headers["foo"] = "bar";
2605 const unsigned char kV2FrameData[] = {
2606 0x80, spdy_version_ch_, 0x00, 0x08,
2607 0x00, 0x00, 0x00, 0x1C,
2608 0x00, 0x00, 0x00, 0x01,
2609 0x00, 0x00, 0x00, 0x02,
2610 0x00, 0x03, 'b', 'a',
2611 'r', 0x00, 0x03, 'f',
2612 'o', 'o', 0x00, 0x03,
2613 'f', 'o', 'o', 0x00,
2614 0x03, 'b', 'a', 'r'
2616 const unsigned char kV3FrameData[] = {
2617 0x80, spdy_version_ch_, 0x00, 0x08,
2618 0x00, 0x00, 0x00, 0x24,
2619 0x00, 0x00, 0x00, 0x01,
2620 0x00, 0x00, 0x00, 0x02,
2621 0x00, 0x00, 0x00, 0x03,
2622 'b', 'a', 'r', 0x00,
2623 0x00, 0x00, 0x03, 'f',
2624 'o', 'o', 0x00, 0x00,
2625 0x00, 0x03, 'f', 'o',
2626 'o', 0x00, 0x00, 0x00,
2627 0x03, 'b', 'a', 'r'
2629 const unsigned char kV4FrameData[] = {
2630 0x00, 0x28, 0x08, 0x00,
2631 0x00, 0x00, 0x00, 0x01,
2632 0x00, 0x00, 0x00, 0x02,
2633 0x00, 0x00, 0x00, 0x03,
2634 'b', 'a', 'r', 0x00,
2635 0x00, 0x00, 0x03, 'f',
2636 'o', 'o', 0x00, 0x00,
2637 0x00, 0x03, 'f', 'o',
2638 'o', 0x00, 0x00, 0x00,
2639 0x03, 'b', 'a', 'r'
2641 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
2642 1, CONTROL_FLAG_NONE, false, &headers));
2643 if (IsSpdy2()) {
2644 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2645 } else if (IsSpdy3()) {
2646 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2647 } else {
2648 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2653 const char kDescription[] =
2654 "HEADERS frame with a 0-length header name, FIN, max stream ID";
2656 SpdyHeaderBlock headers;
2657 headers[std::string()] = "foo";
2658 headers["foo"] = "bar";
2660 const unsigned char kV2FrameData[] = {
2661 0x80, spdy_version_ch_, 0x00, 0x08,
2662 0x01, 0x00, 0x00, 0x19,
2663 0x7f, 0xff, 0xff, 0xff,
2664 0x00, 0x00, 0x00, 0x02,
2665 0x00, 0x00, 0x00, 0x03,
2666 'f', 'o', 'o', 0x00,
2667 0x03, 'f', 'o', 'o',
2668 0x00, 0x03, 'b', 'a',
2671 const unsigned char kV3FrameData[] = {
2672 0x80, spdy_version_ch_, 0x00, 0x08,
2673 0x01, 0x00, 0x00, 0x21,
2674 0x7f, 0xff, 0xff, 0xff,
2675 0x00, 0x00, 0x00, 0x02,
2676 0x00, 0x00, 0x00, 0x00,
2677 0x00, 0x00, 0x00, 0x03,
2678 'f', 'o', 'o', 0x00,
2679 0x00, 0x00, 0x03, 'f',
2680 'o', 'o', 0x00, 0x00,
2681 0x00, 0x03, 'b', 'a',
2684 const unsigned char kV4FrameData[] = {
2685 0x00, 0x25, 0x08, 0x01,
2686 0x7f, 0xff, 0xff, 0xff,
2687 0x00, 0x00, 0x00, 0x02,
2688 0x00, 0x00, 0x00, 0x00,
2689 0x00, 0x00, 0x00, 0x03,
2690 'f', 'o', 'o', 0x00,
2691 0x00, 0x00, 0x03, 'f',
2692 'o', 'o', 0x00, 0x00,
2693 0x00, 0x03, 'b', 'a',
2696 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
2697 0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
2698 if (IsSpdy2()) {
2699 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2700 } else if (IsSpdy3()) {
2701 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2702 } else {
2703 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2708 const char kDescription[] =
2709 "HEADERS frame with a 0-length header val, FIN, max stream ID";
2711 SpdyHeaderBlock headers;
2712 headers["bar"] = "foo";
2713 headers["foo"] = "";
2715 const unsigned char kV2FrameData[] = {
2716 0x80, spdy_version_ch_, 0x00, 0x08,
2717 0x01, 0x00, 0x00, 0x19,
2718 0x7f, 0xff, 0xff, 0xff,
2719 0x00, 0x00, 0x00, 0x02,
2720 0x00, 0x03, 'b', 'a',
2721 'r', 0x00, 0x03, 'f',
2722 'o', 'o', 0x00, 0x03,
2723 'f', 'o', 'o', 0x00,
2724 0x00
2726 const unsigned char kV3FrameData[] = {
2727 0x80, spdy_version_ch_, 0x00, 0x08,
2728 0x01, 0x00, 0x00, 0x21,
2729 0x7f, 0xff, 0xff, 0xff,
2730 0x00, 0x00, 0x00, 0x02,
2731 0x00, 0x00, 0x00, 0x03,
2732 'b', 'a', 'r', 0x00,
2733 0x00, 0x00, 0x03, 'f',
2734 'o', 'o', 0x00, 0x00,
2735 0x00, 0x03, 'f', 'o',
2736 'o', 0x00, 0x00, 0x00,
2737 0x00
2739 const unsigned char kV4FrameData[] = {
2740 0x00, 0x25, 0x08, 0x01,
2741 0x7f, 0xff, 0xff, 0xff,
2742 0x00, 0x00, 0x00, 0x02,
2743 0x00, 0x00, 0x00, 0x03,
2744 'b', 'a', 'r', 0x00,
2745 0x00, 0x00, 0x03, 'f',
2746 'o', 'o', 0x00, 0x00,
2747 0x00, 0x03, 'f', 'o',
2748 'o', 0x00, 0x00, 0x00,
2749 0x00
2751 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
2752 0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
2753 if (IsSpdy2()) {
2754 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2755 } else if (IsSpdy3()) {
2756 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2757 } else {
2758 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2763 // TODO(phajdan.jr): Clean up after we no longer need
2764 // to workaround http://crbug.com/139744.
2765 #if !defined(USE_SYSTEM_ZLIB)
2766 TEST_P(SpdyFramerTest, CreateHeadersCompressed) {
2767 SpdyFramer framer(spdy_version_);
2768 framer.set_enable_compression(true);
2771 const char kDescription[] = "HEADERS frame, no FIN";
2773 SpdyHeaderBlock headers;
2774 headers["bar"] = "foo";
2775 headers["foo"] = "bar";
2777 const unsigned char kV2FrameData[] = {
2778 0x80, spdy_version_ch_, 0x00, 0x08,
2779 0x00, 0x00, 0x00, 0x32,
2780 0x00, 0x00, 0x00, 0x01,
2781 0x00, 0x00, 0x38, 0xea,
2782 0xdf, 0xa2, 0x51, 0xb2,
2783 0x62, 0x60, 0x62, 0x60,
2784 0x4e, 0x4a, 0x2c, 0x62,
2785 0x60, 0x06, 0x08, 0xa0,
2786 0xb4, 0xfc, 0x7c, 0x80,
2787 0x00, 0x62, 0x60, 0x4e,
2788 0xcb, 0xcf, 0x67, 0x60,
2789 0x06, 0x08, 0xa0, 0xa4,
2790 0xc4, 0x22, 0x80, 0x00,
2791 0x02, 0x00, 0x00, 0x00,
2792 0xff, 0xff,
2794 const unsigned char kV3FrameData[] = {
2795 0x80, spdy_version_ch_, 0x00, 0x08,
2796 0x00, 0x00, 0x00, 0x31,
2797 0x00, 0x00, 0x00, 0x01,
2798 0x38, 0xea, 0xe3, 0xc6,
2799 0xa7, 0xc2, 0x02, 0xe5,
2800 0x0e, 0x50, 0xc2, 0x4b,
2801 0x4a, 0x04, 0xe5, 0x0b,
2802 0x66, 0x80, 0x00, 0x4a,
2803 0xcb, 0xcf, 0x07, 0x08,
2804 0x20, 0x10, 0x95, 0x96,
2805 0x9f, 0x0f, 0xa2, 0x00,
2806 0x02, 0x28, 0x29, 0xb1,
2807 0x08, 0x20, 0x80, 0x00,
2808 0x00, 0x00, 0x00, 0xff,
2809 0xff,
2811 const unsigned char kV4FrameData[] = {
2812 0x00, 0x35, 0x08, 0x00,
2813 0x00, 0x00, 0x00, 0x01,
2814 0x38, 0xea, 0xe3, 0xc6,
2815 0xa7, 0xc2, 0x02, 0xe5,
2816 0x0e, 0x50, 0xc2, 0x4b,
2817 0x4a, 0x04, 0xe5, 0x0b,
2818 0x66, 0x80, 0x00, 0x4a,
2819 0xcb, 0xcf, 0x07, 0x08,
2820 0x20, 0x10, 0x95, 0x96,
2821 0x9f, 0x0f, 0xa2, 0x00,
2822 0x02, 0x28, 0x29, 0xb1,
2823 0x08, 0x20, 0x80, 0x00,
2824 0x00, 0x00, 0x00, 0xff,
2825 0xff
2827 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
2828 1, CONTROL_FLAG_NONE, true, &headers));
2829 if (IsSpdy2()) {
2830 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2831 } else if (IsSpdy3()) {
2832 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2833 } else {
2834 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2838 #endif // !defined(USE_SYSTEM_ZLIB)
2840 TEST_P(SpdyFramerTest, CreateWindowUpdate) {
2841 SpdyFramer framer(spdy_version_);
2844 const char kDescription[] = "WINDOW_UPDATE frame";
2845 const unsigned char kV3FrameData[] = { // Also applies for V2.
2846 0x80, spdy_version_ch_, 0x00, 0x09,
2847 0x00, 0x00, 0x00, 0x08,
2848 0x00, 0x00, 0x00, 0x01,
2849 0x00, 0x00, 0x00, 0x01,
2851 const unsigned char kV4FrameData[] = {
2852 0x00, 0x0c, 0x09, 0x00,
2853 0x00, 0x00, 0x00, 0x01,
2854 0x00, 0x00, 0x00, 0x01,
2856 scoped_ptr<SpdyFrame> frame(
2857 framer.CreateWindowUpdate(1, 1));
2858 if (IsSpdy4()) {
2859 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2860 } else {
2861 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2866 const char kDescription[] = "WINDOW_UPDATE frame with max stream ID";
2867 const unsigned char kV3FrameData[] = { // Also applies for V2.
2868 0x80, spdy_version_ch_, 0x00, 0x09,
2869 0x00, 0x00, 0x00, 0x08,
2870 0x7f, 0xff, 0xff, 0xff,
2871 0x00, 0x00, 0x00, 0x01,
2873 const unsigned char kV4FrameData[] = {
2874 0x00, 0x0c, 0x09, 0x00,
2875 0x7f, 0xff, 0xff, 0xff,
2876 0x00, 0x00, 0x00, 0x01,
2878 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(0x7FFFFFFF, 1));
2879 if (IsSpdy4()) {
2880 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2881 } else {
2882 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2887 const char kDescription[] = "WINDOW_UPDATE frame with max window delta";
2888 const unsigned char kV3FrameData[] = { // Also applies for V2.
2889 0x80, spdy_version_ch_, 0x00, 0x09,
2890 0x00, 0x00, 0x00, 0x08,
2891 0x00, 0x00, 0x00, 0x01,
2892 0x7f, 0xff, 0xff, 0xff,
2894 const unsigned char kV4FrameData[] = {
2895 0x00, 0x0c, 0x09, 0x00,
2896 0x00, 0x00, 0x00, 0x01,
2897 0x7f, 0xff, 0xff, 0xff,
2899 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x7FFFFFFF));
2900 if (IsSpdy4()) {
2901 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2902 } else {
2903 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2908 TEST_P(SpdyFramerTest, SerializeBlocked) {
2909 if (spdy_version_ < SPDY4) {
2910 return;
2913 SpdyFramer framer(spdy_version_);
2915 const char kDescription[] = "BLOCKED frame";
2916 const unsigned char kFrameData[] = {
2917 0x00, 0x08, 0x0b, 0x00,
2918 0x00, 0x00, 0x00, 0x00,
2920 SpdyBlockedIR blocked_ir(0);
2921 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeBlocked(blocked_ir));
2922 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
2926 TEST_P(SpdyFramerTest, ReadCompressedSynStreamHeaderBlock) {
2927 SpdyHeaderBlock headers;
2928 headers["aa"] = "vv";
2929 headers["bb"] = "ww";
2930 SpdyFramer framer(spdy_version_);
2931 scoped_ptr<SpdyFrame> control_frame(
2932 framer.CreateSynStream(1, // stream_id
2933 0, // associated_stream_id
2934 1, // priority
2935 0, // credential_slot
2936 CONTROL_FLAG_NONE,
2937 true, // compress
2938 &headers));
2939 EXPECT_TRUE(control_frame.get() != NULL);
2940 TestSpdyVisitor visitor(spdy_version_);
2941 visitor.use_compression_ = true;
2942 visitor.SimulateInFramer(
2943 reinterpret_cast<unsigned char*>(control_frame->data()),
2944 control_frame->size());
2945 EXPECT_EQ(1, visitor.syn_frame_count_);
2946 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
2949 TEST_P(SpdyFramerTest, ReadCompressedSynReplyHeaderBlock) {
2950 SpdyHeaderBlock headers;
2951 headers["alpha"] = "beta";
2952 headers["gamma"] = "delta";
2953 SpdyFramer framer(spdy_version_);
2954 scoped_ptr<SpdyFrame> control_frame(
2955 framer.CreateSynReply(1, // stream_id
2956 CONTROL_FLAG_NONE,
2957 true, // compress
2958 &headers));
2959 EXPECT_TRUE(control_frame.get() != NULL);
2960 TestSpdyVisitor visitor(spdy_version_);
2961 visitor.use_compression_ = true;
2962 visitor.SimulateInFramer(
2963 reinterpret_cast<unsigned char*>(control_frame->data()),
2964 control_frame->size());
2965 EXPECT_EQ(1, visitor.syn_reply_frame_count_);
2966 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
2969 TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) {
2970 SpdyHeaderBlock headers;
2971 headers["alpha"] = "beta";
2972 headers["gamma"] = "delta";
2973 SpdyFramer framer(spdy_version_);
2974 scoped_ptr<SpdyFrame> control_frame(
2975 framer.CreateHeaders(1, // stream_id
2976 CONTROL_FLAG_NONE,
2977 true, // compress
2978 &headers));
2979 EXPECT_TRUE(control_frame.get() != NULL);
2980 TestSpdyVisitor visitor(spdy_version_);
2981 visitor.use_compression_ = true;
2982 visitor.SimulateInFramer(
2983 reinterpret_cast<unsigned char*>(control_frame->data()),
2984 control_frame->size());
2985 EXPECT_EQ(1, visitor.headers_frame_count_);
2986 // control_frame_header_data_count_ depends on the random sequence
2987 // produced by rand(), so adding, removing or running single tests
2988 // alters this value. The best we can do is assert that it happens
2989 // at least twice.
2990 EXPECT_LE(2, visitor.control_frame_header_data_count_);
2991 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
2992 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
2993 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
2996 TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) {
2997 SpdyHeaderBlock headers;
2998 headers["alpha"] = "beta";
2999 headers["gamma"] = "delta";
3000 SpdyFramer framer(spdy_version_);
3001 scoped_ptr<SpdyFrame> control_frame(
3002 framer.CreateHeaders(1, // stream_id
3003 CONTROL_FLAG_FIN,
3004 true, // compress
3005 &headers));
3006 EXPECT_TRUE(control_frame.get() != NULL);
3007 TestSpdyVisitor visitor(spdy_version_);
3008 visitor.use_compression_ = true;
3009 visitor.SimulateInFramer(
3010 reinterpret_cast<unsigned char*>(control_frame->data()),
3011 control_frame->size());
3012 EXPECT_EQ(1, visitor.headers_frame_count_);
3013 // control_frame_header_data_count_ depends on the random sequence
3014 // produced by rand(), so adding, removing or running single tests
3015 // alters this value. The best we can do is assert that it happens
3016 // at least twice.
3017 EXPECT_LE(2, visitor.control_frame_header_data_count_);
3018 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
3019 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
3020 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
3023 TEST_P(SpdyFramerTest, ControlFrameAtMaxSizeLimit) {
3024 // First find the size of the header value in order to just reach the control
3025 // frame max size.
3026 SpdyFramer framer(spdy_version_);
3027 framer.set_enable_compression(false);
3028 SpdyHeaderBlock headers;
3029 headers["aa"] = "";
3030 scoped_ptr<SpdyFrame> control_frame(
3031 framer.CreateSynStream(1, // stream_id
3032 0, // associated_stream_id
3033 1, // priority
3034 0, // credential_slot
3035 CONTROL_FLAG_NONE,
3036 false, // compress
3037 &headers));
3038 const size_t kBigValueSize =
3039 framer.GetControlFrameBufferMaxSize() - control_frame->size();
3041 // Create a frame at exatly that size.
3042 string big_value(kBigValueSize, 'x');
3043 headers["aa"] = big_value.c_str();
3044 control_frame.reset(
3045 framer.CreateSynStream(1, // stream_id
3046 0, // associated_stream_id
3047 1, // priority
3048 0, // credential_slot
3049 CONTROL_FLAG_NONE,
3050 false, // compress
3051 &headers));
3052 EXPECT_TRUE(control_frame.get() != NULL);
3053 EXPECT_EQ(framer.GetControlFrameBufferMaxSize(), control_frame->size());
3055 TestSpdyVisitor visitor(spdy_version_);
3056 visitor.SimulateInFramer(
3057 reinterpret_cast<unsigned char*>(control_frame->data()),
3058 control_frame->size());
3059 EXPECT_TRUE(visitor.header_buffer_valid_);
3060 EXPECT_EQ(0, visitor.error_count_);
3061 EXPECT_EQ(1, visitor.syn_frame_count_);
3062 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
3063 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
3064 EXPECT_LT(kBigValueSize, visitor.header_buffer_length_);
3067 TEST_P(SpdyFramerTest, ControlFrameTooLarge) {
3068 // First find the size of the header value in order to just reach the control
3069 // frame max size.
3070 SpdyFramer framer(spdy_version_);
3071 framer.set_enable_compression(false);
3072 SpdyHeaderBlock headers;
3073 headers["aa"] = "";
3074 scoped_ptr<SpdyFrame> control_frame(
3075 framer.CreateSynStream(1, // stream_id
3076 0, // associated_stream_id
3077 1, // priority
3078 0, // credential_slot
3079 CONTROL_FLAG_NONE,
3080 false, // compress
3081 &headers));
3082 const size_t kBigValueSize =
3083 framer.GetControlFrameBufferMaxSize() - control_frame->size() + 1;
3085 // Create a frame at exatly that size.
3086 string big_value(kBigValueSize, 'x');
3087 headers["aa"] = big_value.c_str();
3088 control_frame.reset(
3089 framer.CreateSynStream(1, // stream_id
3090 0, // associated_stream_id
3091 1, // priority
3092 0, // credential_slot
3093 CONTROL_FLAG_NONE,
3094 false, // compress
3095 &headers));
3096 EXPECT_TRUE(control_frame.get() != NULL);
3097 EXPECT_EQ(framer.GetControlFrameBufferMaxSize() + 1,
3098 control_frame->size());
3100 TestSpdyVisitor visitor(spdy_version_);
3101 visitor.SimulateInFramer(
3102 reinterpret_cast<unsigned char*>(control_frame->data()),
3103 control_frame->size());
3104 EXPECT_FALSE(visitor.header_buffer_valid_);
3105 EXPECT_EQ(1, visitor.error_count_);
3106 EXPECT_EQ(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE,
3107 visitor.framer_.error_code());
3108 EXPECT_EQ(0, visitor.syn_frame_count_);
3109 EXPECT_EQ(0u, visitor.header_buffer_length_);
3112 // Check that the framer stops delivering header data chunks once the visitor
3113 // declares it doesn't want any more. This is important to guard against
3114 // "zip bomb" types of attacks.
3115 TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) {
3116 SpdyHeaderBlock headers;
3117 const size_t kHeaderBufferChunks = 4;
3118 const size_t kHeaderBufferSize =
3119 TestSpdyVisitor::header_data_chunk_max_size() * kHeaderBufferChunks;
3120 const size_t kBigValueSize = kHeaderBufferSize * 2;
3121 string big_value(kBigValueSize, 'x');
3122 headers["aa"] = big_value.c_str();
3123 SpdyFramer framer(spdy_version_);
3124 scoped_ptr<SpdyFrame> control_frame(
3125 framer.CreateSynStream(1, // stream_id
3126 0, // associated_stream_id
3127 1, // priority
3128 0, // credential_slot
3129 CONTROL_FLAG_FIN, // half close
3130 true, // compress
3131 &headers));
3132 EXPECT_TRUE(control_frame.get() != NULL);
3133 TestSpdyVisitor visitor(spdy_version_);
3134 visitor.set_header_buffer_size(kHeaderBufferSize);
3135 visitor.use_compression_ = true;
3136 visitor.SimulateInFramer(
3137 reinterpret_cast<unsigned char*>(control_frame->data()),
3138 control_frame->size());
3139 EXPECT_FALSE(visitor.header_buffer_valid_);
3140 EXPECT_EQ(1, visitor.error_count_);
3141 EXPECT_EQ(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE,
3142 visitor.framer_.error_code());
3144 // The framer should have stoped delivering chunks after the visitor
3145 // signaled "stop" by returning false from OnControlFrameHeaderData().
3147 // control_frame_header_data_count_ depends on the random sequence
3148 // produced by rand(), so adding, removing or running single tests
3149 // alters this value. The best we can do is assert that it happens
3150 // at least kHeaderBufferChunks + 1.
3151 EXPECT_LE(kHeaderBufferChunks + 1,
3152 static_cast<unsigned>(visitor.control_frame_header_data_count_));
3153 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
3155 // The framer should not have sent half-close to the visitor.
3156 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
3159 TEST_P(SpdyFramerTest, DecompressCorruptHeaderBlock) {
3160 SpdyHeaderBlock headers;
3161 headers["aa"] = "alpha beta gamma delta";
3162 SpdyFramer framer(spdy_version_);
3163 framer.set_enable_compression(false);
3164 // Construct a SYN_STREAM control frame without compressing the header block,
3165 // and have the framer try to decompress it. This will cause the framer to
3166 // deal with a decompression error.
3167 scoped_ptr<SpdyFrame> control_frame(
3168 framer.CreateSynStream(1, // stream_id
3169 0, // associated_stream_id
3170 1, // priority
3171 0, // credential_slot
3172 CONTROL_FLAG_NONE,
3173 false, // compress
3174 &headers));
3175 TestSpdyVisitor visitor(spdy_version_);
3176 visitor.use_compression_ = true;
3177 visitor.SimulateInFramer(
3178 reinterpret_cast<unsigned char*>(control_frame->data()),
3179 control_frame->size());
3180 EXPECT_EQ(1, visitor.error_count_);
3181 EXPECT_EQ(SpdyFramer::SPDY_DECOMPRESS_FAILURE, visitor.framer_.error_code());
3182 EXPECT_EQ(0u, visitor.header_buffer_length_);
3185 TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) {
3186 // Create a GoAway frame that has a few extra bytes at the end.
3187 // We create enough overhead to overflow the framer's control frame buffer.
3188 ASSERT_GE(250u, SpdyFramer::kControlFrameBufferSize);
3189 const unsigned char length = 1 + SpdyFramer::kControlFrameBufferSize;
3190 const unsigned char kV3FrameData[] = { // Also applies for V2.
3191 0x80, spdy_version_ch_, 0x00, 0x07,
3192 0x00, 0x00, 0x00, length,
3193 0x00, 0x00, 0x00, 0x00,
3194 0x00, 0x00, 0x00, 0x00,
3196 const unsigned char kV4FrameData[] = {
3197 0x00, static_cast<uint8>(length + 4), 0x07, 0x00,
3198 0x00, 0x00, 0x00, 0x00,
3199 0x00, 0x00, 0x00, 0x00,
3201 SpdyFramer framer(spdy_version_);
3202 const size_t pad_length =
3203 length + framer.GetControlFrameHeaderSize() -
3204 (IsSpdy4() ? sizeof(kV4FrameData) : sizeof(kV3FrameData));
3205 string pad('A', pad_length);
3206 TestSpdyVisitor visitor(spdy_version_);
3208 if (IsSpdy4()) {
3209 visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData));
3210 } else {
3211 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
3213 visitor.SimulateInFramer(
3214 reinterpret_cast<const unsigned char*>(pad.c_str()),
3215 pad.length());
3217 EXPECT_EQ(1, visitor.error_count_); // This generated an error.
3218 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME,
3219 visitor.framer_.error_code());
3220 EXPECT_EQ(0, visitor.goaway_count_); // Frame not parsed.
3223 TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) {
3224 SpdyFramer framer(spdy_version_);
3225 SettingsMap settings;
3226 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
3227 SetFrameLength(control_frame.get(), 0, spdy_version_);
3228 TestSpdyVisitor visitor(spdy_version_);
3229 visitor.use_compression_ = false;
3230 visitor.SimulateInFramer(
3231 reinterpret_cast<unsigned char*>(control_frame->data()),
3232 framer.GetControlFrameHeaderSize());
3233 // Should generate an error, since zero-len settings frames are unsupported.
3234 EXPECT_EQ(1, visitor.error_count_);
3237 // Tests handling of SETTINGS frames with invalid length.
3238 TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) {
3239 SpdyFramer framer(spdy_version_);
3240 SettingsMap settings;
3241 // Add a setting to pad the frame so that we don't get a buffer overflow when
3242 // calling SimulateInFramer() below.
3243 settings[SETTINGS_UPLOAD_BANDWIDTH] =
3244 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, 0x00000002);
3245 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
3246 const size_t kNewLength = 5;
3247 SetFrameLength(control_frame.get(), kNewLength, spdy_version_);
3248 TestSpdyVisitor visitor(spdy_version_);
3249 visitor.use_compression_ = false;
3250 visitor.SimulateInFramer(
3251 reinterpret_cast<unsigned char*>(control_frame->data()),
3252 framer.GetControlFrameHeaderSize() + kNewLength);
3253 // Should generate an error, since zero-len settings frames are unsupported.
3254 EXPECT_EQ(1, visitor.error_count_);
3257 // Tests handling of SETTINGS frames larger than the frame buffer size.
3258 TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) {
3259 SpdyFramer framer(spdy_version_);
3260 SettingsMap settings;
3261 SpdySettingsFlags flags = SETTINGS_FLAG_PLEASE_PERSIST;
3262 settings[SETTINGS_UPLOAD_BANDWIDTH] =
3263 SettingsFlagsAndValue(flags, 0x00000002);
3264 settings[SETTINGS_DOWNLOAD_BANDWIDTH] =
3265 SettingsFlagsAndValue(flags, 0x00000003);
3266 settings[SETTINGS_ROUND_TRIP_TIME] = SettingsFlagsAndValue(flags, 0x00000004);
3267 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
3268 EXPECT_LT(SpdyFramer::kControlFrameBufferSize,
3269 control_frame->size());
3270 TestSpdyVisitor visitor(spdy_version_);
3271 visitor.use_compression_ = false;
3273 // Read all at once.
3274 visitor.SimulateInFramer(
3275 reinterpret_cast<unsigned char*>(control_frame->data()),
3276 control_frame->size());
3277 EXPECT_EQ(0, visitor.error_count_);
3278 EXPECT_EQ(settings.size(), static_cast<unsigned>(visitor.setting_count_));
3280 // Read data in small chunks.
3281 size_t framed_data = 0;
3282 size_t unframed_data = control_frame->size();
3283 size_t kReadChunkSize = 5; // Read five bytes at a time.
3284 while (unframed_data > 0) {
3285 size_t to_read = min(kReadChunkSize, unframed_data);
3286 visitor.SimulateInFramer(
3287 reinterpret_cast<unsigned char*>(control_frame->data() + framed_data),
3288 to_read);
3289 unframed_data -= to_read;
3290 framed_data += to_read;
3292 EXPECT_EQ(0, visitor.error_count_);
3293 EXPECT_EQ(settings.size() * 2, static_cast<unsigned>(visitor.setting_count_));
3296 // Tests handling of SETTINGS frame with duplicate entries.
3297 TEST_P(SpdyFramerTest, ReadDuplicateSettings) {
3298 SpdyFramer framer(spdy_version_);
3300 const unsigned char kV2FrameData[] = {
3301 0x80, spdy_version_ch_, 0x00, 0x04,
3302 0x00, 0x00, 0x00, 0x1C,
3303 0x00, 0x00, 0x00, 0x03,
3304 0x01, 0x00, 0x00, 0x00, // 1st Setting
3305 0x00, 0x00, 0x00, 0x02,
3306 0x01, 0x00, 0x00, 0x00, // 2nd (duplicate) Setting
3307 0x00, 0x00, 0x00, 0x03,
3308 0x03, 0x00, 0x00, 0x00, // 3rd (unprocessed) Setting
3309 0x00, 0x00, 0x00, 0x03,
3311 const unsigned char kV3FrameData[] = {
3312 0x80, spdy_version_ch_, 0x00, 0x04,
3313 0x00, 0x00, 0x00, 0x1C,
3314 0x00, 0x00, 0x00, 0x03,
3315 0x00, 0x00, 0x00, 0x01, // 1st Setting
3316 0x00, 0x00, 0x00, 0x02,
3317 0x00, 0x00, 0x00, 0x01, // 2nd (duplicate) Setting
3318 0x00, 0x00, 0x00, 0x03,
3319 0x00, 0x00, 0x00, 0x03, // 3rd (unprocessed) Setting
3320 0x00, 0x00, 0x00, 0x03,
3322 const unsigned char kV4FrameData[] = {
3323 0x00, 0x24, 0x04, 0x00,
3324 0x00, 0x00, 0x00, 0x00,
3325 0x00, 0x00, 0x00, 0x03,
3326 0x00, 0x00, 0x00, 0x01, // 1st Setting
3327 0x00, 0x00, 0x00, 0x02,
3328 0x00, 0x00, 0x00, 0x01, // 2nd (duplicate) Setting
3329 0x00, 0x00, 0x00, 0x03,
3330 0x00, 0x00, 0x00, 0x03, // 3rd (unprocessed) Setting
3331 0x00, 0x00, 0x00, 0x03,
3334 TestSpdyVisitor visitor(spdy_version_);
3335 visitor.use_compression_ = false;
3336 if (IsSpdy2()) {
3337 visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData));
3338 } else if (IsSpdy3()) {
3339 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
3340 } else {
3341 visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData));
3343 EXPECT_EQ(1, visitor.error_count_);
3344 EXPECT_EQ(1, visitor.setting_count_);
3347 // Tests handling of SETTINGS frame with entries out of order.
3348 TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) {
3349 SpdyFramer framer(spdy_version_);
3351 const unsigned char kV2FrameData[] = {
3352 0x80, spdy_version_ch_, 0x00, 0x04,
3353 0x00, 0x00, 0x00, 0x1C,
3354 0x00, 0x00, 0x00, 0x03,
3355 0x02, 0x00, 0x00, 0x00, // 1st Setting
3356 0x00, 0x00, 0x00, 0x02,
3357 0x01, 0x00, 0x00, 0x00, // 2nd (out of order) Setting
3358 0x00, 0x00, 0x00, 0x03,
3359 0x03, 0x00, 0x00, 0x00, // 3rd (unprocessed) Setting
3360 0x00, 0x00, 0x00, 0x03,
3362 const unsigned char kV3FrameData[] = {
3363 0x80, spdy_version_ch_, 0x00, 0x04,
3364 0x00, 0x00, 0x00, 0x1C,
3365 0x00, 0x00, 0x00, 0x03,
3366 0x00, 0x00, 0x00, 0x02, // 1st Setting
3367 0x00, 0x00, 0x00, 0x02,
3368 0x00, 0x00, 0x00, 0x01, // 2nd (out of order) Setting
3369 0x00, 0x00, 0x00, 0x03,
3370 0x00, 0x00, 0x01, 0x03, // 3rd (unprocessed) Setting
3371 0x00, 0x00, 0x00, 0x03,
3373 const unsigned char kV4FrameData[] = {
3374 0x00, 0x24, 0x04, 0x00,
3375 0x00, 0x00, 0x00, 0x00,
3376 0x00, 0x00, 0x00, 0x03,
3377 0x00, 0x00, 0x00, 0x02, // 1st Setting
3378 0x00, 0x00, 0x00, 0x02,
3379 0x00, 0x00, 0x00, 0x01, // 2nd (out of order) Setting
3380 0x00, 0x00, 0x00, 0x03,
3381 0x00, 0x00, 0x01, 0x03, // 3rd (unprocessed) Setting
3382 0x00, 0x00, 0x00, 0x03,
3385 TestSpdyVisitor visitor(spdy_version_);
3386 visitor.use_compression_ = false;
3387 if (IsSpdy2()) {
3388 visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData));
3389 } else if (IsSpdy3()) {
3390 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
3391 } else {
3392 visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData));
3394 EXPECT_EQ(1, visitor.error_count_);
3395 EXPECT_EQ(1, visitor.setting_count_);
3398 TEST_P(SpdyFramerTest, ReadWindowUpdate) {
3399 SpdyFramer framer(spdy_version_);
3400 scoped_ptr<SpdyFrame> control_frame(
3401 framer.CreateWindowUpdate(1, 2));
3402 TestSpdyVisitor visitor(spdy_version_);
3403 visitor.SimulateInFramer(
3404 reinterpret_cast<unsigned char*>(control_frame->data()),
3405 control_frame->size());
3406 EXPECT_EQ(1u, visitor.last_window_update_stream_);
3407 EXPECT_EQ(2u, visitor.last_window_update_delta_);
3410 TEST_P(SpdyFramerTest, ReadCredentialFrame) {
3411 SpdyCredential credential;
3412 credential.slot = 3;
3413 credential.proof = "proof";
3414 credential.certs.push_back("a cert");
3415 credential.certs.push_back("another cert");
3416 credential.certs.push_back("final cert");
3417 SpdyFramer framer(spdy_version_);
3418 scoped_ptr<SpdyFrame> control_frame(
3419 framer.CreateCredentialFrame(credential));
3420 EXPECT_TRUE(control_frame.get() != NULL);
3421 TestSpdyVisitor visitor(spdy_version_);
3422 visitor.use_compression_ = false;
3423 visitor.SimulateInFramer(
3424 reinterpret_cast<unsigned char*>(control_frame->data()),
3425 control_frame->size());
3426 EXPECT_EQ(0, visitor.error_count_);
3427 EXPECT_EQ(control_frame->size() - framer.GetControlFrameHeaderSize(),
3428 visitor.credential_buffer_length_);
3429 EXPECT_EQ(credential.slot, visitor.credential_.slot);
3430 EXPECT_EQ(credential.proof, visitor.credential_.proof);
3431 EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size());
3432 for (size_t i = 0; i < credential.certs.size(); i++) {
3433 EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]);
3437 TEST_P(SpdyFramerTest, ReadCredentialFrameOneByteAtATime) {
3438 SpdyCredential credential;
3439 credential.slot = 3;
3440 credential.proof = "proof";
3441 credential.certs.push_back("a cert");
3442 credential.certs.push_back("another cert");
3443 credential.certs.push_back("final cert");
3444 SpdyFramer framer(spdy_version_);
3445 scoped_ptr<SpdyFrame> control_frame(
3446 framer.CreateCredentialFrame(credential));
3447 EXPECT_TRUE(control_frame.get() != NULL);
3448 TestSpdyVisitor visitor(spdy_version_);
3449 visitor.use_compression_ = false;
3450 // Read one byte at a time to make sure we handle edge cases
3451 unsigned char* data =
3452 reinterpret_cast<unsigned char*>(control_frame->data());
3453 for (size_t idx = 0; idx < control_frame->size(); ++idx) {
3454 visitor.SimulateInFramer(data + idx, 1);
3455 ASSERT_EQ(0, visitor.error_count_);
3457 EXPECT_EQ(0, visitor.error_count_);
3458 EXPECT_EQ(control_frame->size() - framer.GetControlFrameHeaderSize(),
3459 visitor.credential_buffer_length_);
3460 EXPECT_EQ(credential.slot, visitor.credential_.slot);
3461 EXPECT_EQ(credential.proof, visitor.credential_.proof);
3462 EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size());
3463 for (size_t i = 0; i < credential.certs.size(); i++) {
3464 EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]);
3468 TEST_P(SpdyFramerTest, ReadCredentialFrameWithNoPayload) {
3469 SpdyCredential credential;
3470 credential.slot = 3;
3471 credential.proof = "proof";
3472 credential.certs.push_back("a cert");
3473 credential.certs.push_back("another cert");
3474 credential.certs.push_back("final cert");
3475 SpdyFramer framer(spdy_version_);
3476 scoped_ptr<SpdyFrame> control_frame(
3477 framer.CreateCredentialFrame(credential));
3478 EXPECT_TRUE(control_frame.get() != NULL);
3479 TestSpdyVisitor visitor(spdy_version_);
3480 visitor.use_compression_ = false;
3481 SetFrameLength(control_frame.get(), 0, spdy_version_);
3482 unsigned char* data =
3483 reinterpret_cast<unsigned char*>(control_frame->data());
3484 visitor.SimulateInFramer(data, framer.GetControlFrameHeaderSize());
3485 EXPECT_EQ(1, visitor.error_count_);
3488 TEST_P(SpdyFramerTest, ReadCredentialFrameWithCorruptProof) {
3489 SpdyCredential credential;
3490 credential.slot = 3;
3491 credential.proof = "proof";
3492 credential.certs.push_back("a cert");
3493 credential.certs.push_back("another cert");
3494 credential.certs.push_back("final cert");
3495 SpdyFramer framer(spdy_version_);
3496 scoped_ptr<SpdyFrame> control_frame(
3497 framer.CreateCredentialFrame(credential));
3498 EXPECT_TRUE(control_frame.get() != NULL);
3499 TestSpdyVisitor visitor(spdy_version_);
3500 visitor.use_compression_ = false;
3501 unsigned char* data =
3502 reinterpret_cast<unsigned char*>(control_frame->data());
3503 size_t offset = framer.GetControlFrameHeaderSize() + 4;
3504 data[offset] = 0xFF; // Proof length is past the end of the frame
3505 visitor.SimulateInFramer(
3506 data, control_frame->size());
3507 EXPECT_EQ(1, visitor.error_count_);
3510 TEST_P(SpdyFramerTest, ReadCredentialFrameWithCorruptCertificate) {
3511 SpdyCredential credential;
3512 credential.slot = 3;
3513 credential.proof = "proof";
3514 credential.certs.push_back("a cert");
3515 credential.certs.push_back("another cert");
3516 credential.certs.push_back("final cert");
3517 SpdyFramer framer(spdy_version_);
3518 scoped_ptr<SpdyFrame> control_frame(
3519 framer.CreateCredentialFrame(credential));
3520 EXPECT_TRUE(control_frame.get() != NULL);
3521 TestSpdyVisitor visitor(spdy_version_);
3522 visitor.use_compression_ = false;
3523 unsigned char* data =
3524 reinterpret_cast<unsigned char*>(control_frame->data());
3525 size_t offset = framer.GetCredentialMinimumSize() + 1;
3526 data[offset] = 0xFF; // Proof length is past the end of the frame
3527 visitor.SimulateInFramer(
3528 data, control_frame->size());
3529 EXPECT_EQ(1, visitor.error_count_);
3532 TEST_P(SpdyFramerTest, ReadGarbage) {
3533 SpdyFramer framer(spdy_version_);
3534 unsigned char garbage_frame[256];
3535 memset(garbage_frame, ~0, sizeof(garbage_frame));
3536 TestSpdyVisitor visitor(spdy_version_);
3537 visitor.use_compression_ = false;
3538 visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame));
3539 EXPECT_EQ(1, visitor.error_count_);
3542 TEST_P(SpdyFramerTest, ReadGarbageWithValidVersion) {
3543 if (IsSpdy4()) {
3544 // Not valid for SPDY 4 since there is no version field.
3545 return;
3547 SpdyFramer framer(spdy_version_);
3548 const unsigned char kFrameData[] = {
3549 0x80, spdy_version_ch_, 0xff, 0xff,
3550 0xff, 0xff, 0xff, 0xff,
3552 TestSpdyVisitor visitor(spdy_version_);
3553 visitor.use_compression_ = false;
3554 visitor.SimulateInFramer(kFrameData, arraysize(kFrameData));
3555 EXPECT_EQ(1, visitor.error_count_);
3558 TEST_P(SpdyFramerTest, SizesTest) {
3559 SpdyFramer framer(spdy_version_);
3560 EXPECT_EQ(8u, framer.GetDataFrameMinimumSize());
3561 if (IsSpdy4()) {
3562 EXPECT_EQ(8u, framer.GetSynReplyMinimumSize());
3563 EXPECT_EQ(12u, framer.GetRstStreamSize());
3564 EXPECT_EQ(12u, framer.GetSettingsMinimumSize());
3565 EXPECT_EQ(12u, framer.GetPingSize());
3566 EXPECT_EQ(16u, framer.GetGoAwaySize());
3567 EXPECT_EQ(8u, framer.GetHeadersMinimumSize());
3568 EXPECT_EQ(12u, framer.GetWindowUpdateSize());
3569 EXPECT_EQ(10u, framer.GetCredentialMinimumSize());
3570 EXPECT_EQ(8u, framer.GetBlockedSize());
3571 EXPECT_EQ(8u, framer.GetFrameMinimumSize());
3572 EXPECT_EQ(65535u, framer.GetFrameMaximumSize());
3573 EXPECT_EQ(65527u, framer.GetDataFrameMaximumPayload());
3574 } else {
3575 EXPECT_EQ(8u, framer.GetControlFrameHeaderSize());
3576 EXPECT_EQ(18u, framer.GetSynStreamMinimumSize());
3577 EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetSynReplyMinimumSize());
3578 EXPECT_EQ(16u, framer.GetRstStreamSize());
3579 EXPECT_EQ(12u, framer.GetSettingsMinimumSize());
3580 EXPECT_EQ(12u, framer.GetPingSize());
3581 EXPECT_EQ(IsSpdy2() ? 12u : 16u, framer.GetGoAwaySize());
3582 EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetHeadersMinimumSize());
3583 EXPECT_EQ(16u, framer.GetWindowUpdateSize());
3584 EXPECT_EQ(10u, framer.GetCredentialMinimumSize());
3585 EXPECT_EQ(8u, framer.GetFrameMinimumSize());
3586 EXPECT_EQ(16777215u, framer.GetFrameMaximumSize());
3587 EXPECT_EQ(16777207u, framer.GetDataFrameMaximumPayload());
3591 TEST_P(SpdyFramerTest, StateToStringTest) {
3592 EXPECT_STREQ("ERROR",
3593 SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR));
3594 EXPECT_STREQ("AUTO_RESET",
3595 SpdyFramer::StateToString(SpdyFramer::SPDY_AUTO_RESET));
3596 EXPECT_STREQ("RESET",
3597 SpdyFramer::StateToString(SpdyFramer::SPDY_RESET));
3598 EXPECT_STREQ("READING_COMMON_HEADER",
3599 SpdyFramer::StateToString(
3600 SpdyFramer::SPDY_READING_COMMON_HEADER));
3601 EXPECT_STREQ("CONTROL_FRAME_PAYLOAD",
3602 SpdyFramer::StateToString(
3603 SpdyFramer::SPDY_CONTROL_FRAME_PAYLOAD));
3604 EXPECT_STREQ("IGNORE_REMAINING_PAYLOAD",
3605 SpdyFramer::StateToString(
3606 SpdyFramer::SPDY_IGNORE_REMAINING_PAYLOAD));
3607 EXPECT_STREQ("FORWARD_STREAM_FRAME",
3608 SpdyFramer::StateToString(
3609 SpdyFramer::SPDY_FORWARD_STREAM_FRAME));
3610 EXPECT_STREQ("SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK",
3611 SpdyFramer::StateToString(
3612 SpdyFramer::SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK));
3613 EXPECT_STREQ("SPDY_CONTROL_FRAME_HEADER_BLOCK",
3614 SpdyFramer::StateToString(
3615 SpdyFramer::SPDY_CONTROL_FRAME_HEADER_BLOCK));
3616 EXPECT_STREQ("SPDY_CREDENTIAL_FRAME_PAYLOAD",
3617 SpdyFramer::StateToString(
3618 SpdyFramer::SPDY_CREDENTIAL_FRAME_PAYLOAD));
3619 EXPECT_STREQ("SPDY_SETTINGS_FRAME_PAYLOAD",
3620 SpdyFramer::StateToString(
3621 SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD));
3622 EXPECT_STREQ("UNKNOWN_STATE",
3623 SpdyFramer::StateToString(
3624 SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD + 1));
3627 TEST_P(SpdyFramerTest, ErrorCodeToStringTest) {
3628 EXPECT_STREQ("NO_ERROR",
3629 SpdyFramer::ErrorCodeToString(SpdyFramer::SPDY_NO_ERROR));
3630 EXPECT_STREQ("INVALID_CONTROL_FRAME",
3631 SpdyFramer::ErrorCodeToString(
3632 SpdyFramer::SPDY_INVALID_CONTROL_FRAME));
3633 EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE",
3634 SpdyFramer::ErrorCodeToString(
3635 SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE));
3636 EXPECT_STREQ("ZLIB_INIT_FAILURE",
3637 SpdyFramer::ErrorCodeToString(
3638 SpdyFramer::SPDY_ZLIB_INIT_FAILURE));
3639 EXPECT_STREQ("UNSUPPORTED_VERSION",
3640 SpdyFramer::ErrorCodeToString(
3641 SpdyFramer::SPDY_UNSUPPORTED_VERSION));
3642 EXPECT_STREQ("DECOMPRESS_FAILURE",
3643 SpdyFramer::ErrorCodeToString(
3644 SpdyFramer::SPDY_DECOMPRESS_FAILURE));
3645 EXPECT_STREQ("COMPRESS_FAILURE",
3646 SpdyFramer::ErrorCodeToString(
3647 SpdyFramer::SPDY_COMPRESS_FAILURE));
3648 EXPECT_STREQ("SPDY_INVALID_DATA_FRAME_FLAGS",
3649 SpdyFramer::ErrorCodeToString(
3650 SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS));
3651 EXPECT_STREQ("SPDY_INVALID_CONTROL_FRAME_FLAGS",
3652 SpdyFramer::ErrorCodeToString(
3653 SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS));
3654 EXPECT_STREQ("UNKNOWN_ERROR",
3655 SpdyFramer::ErrorCodeToString(SpdyFramer::LAST_ERROR));
3658 TEST_P(SpdyFramerTest, StatusCodeToStringTest) {
3659 EXPECT_STREQ("INVALID",
3660 SpdyFramer::StatusCodeToString(RST_STREAM_INVALID));
3661 EXPECT_STREQ("PROTOCOL_ERROR",
3662 SpdyFramer::StatusCodeToString(RST_STREAM_PROTOCOL_ERROR));
3663 EXPECT_STREQ("INVALID_STREAM",
3664 SpdyFramer::StatusCodeToString(RST_STREAM_INVALID_STREAM));
3665 EXPECT_STREQ("REFUSED_STREAM",
3666 SpdyFramer::StatusCodeToString(RST_STREAM_REFUSED_STREAM));
3667 EXPECT_STREQ("UNSUPPORTED_VERSION",
3668 SpdyFramer::StatusCodeToString(RST_STREAM_UNSUPPORTED_VERSION));
3669 EXPECT_STREQ("CANCEL",
3670 SpdyFramer::StatusCodeToString(RST_STREAM_CANCEL));
3671 EXPECT_STREQ("INTERNAL_ERROR",
3672 SpdyFramer::StatusCodeToString(RST_STREAM_INTERNAL_ERROR));
3673 EXPECT_STREQ("FLOW_CONTROL_ERROR",
3674 SpdyFramer::StatusCodeToString(RST_STREAM_FLOW_CONTROL_ERROR));
3675 EXPECT_STREQ("UNKNOWN_STATUS",
3676 SpdyFramer::StatusCodeToString(RST_STREAM_NUM_STATUS_CODES));
3679 TEST_P(SpdyFramerTest, FrameTypeToStringTest) {
3680 EXPECT_STREQ("DATA",
3681 SpdyFramer::FrameTypeToString(DATA));
3682 EXPECT_STREQ("SYN_STREAM",
3683 SpdyFramer::FrameTypeToString(SYN_STREAM));
3684 EXPECT_STREQ("SYN_REPLY",
3685 SpdyFramer::FrameTypeToString(SYN_REPLY));
3686 EXPECT_STREQ("RST_STREAM",
3687 SpdyFramer::FrameTypeToString(RST_STREAM));
3688 EXPECT_STREQ("SETTINGS",
3689 SpdyFramer::FrameTypeToString(SETTINGS));
3690 EXPECT_STREQ("NOOP",
3691 SpdyFramer::FrameTypeToString(NOOP));
3692 EXPECT_STREQ("PING",
3693 SpdyFramer::FrameTypeToString(PING));
3694 EXPECT_STREQ("GOAWAY",
3695 SpdyFramer::FrameTypeToString(GOAWAY));
3696 EXPECT_STREQ("HEADERS",
3697 SpdyFramer::FrameTypeToString(HEADERS));
3698 EXPECT_STREQ("WINDOW_UPDATE",
3699 SpdyFramer::FrameTypeToString(WINDOW_UPDATE));
3700 EXPECT_STREQ("CREDENTIAL",
3701 SpdyFramer::FrameTypeToString(CREDENTIAL));
3704 TEST_P(SpdyFramerTest, CatchProbableHttpResponse) {
3705 if (IsSpdy4()) {
3706 // TODO(hkhalil): catch probable HTTP response in SPDY 4?
3707 return;
3710 testing::StrictMock<test::MockVisitor> visitor;
3711 SpdyFramer framer(spdy_version_);
3712 framer.set_visitor(&visitor);
3714 EXPECT_CALL(visitor, OnError(_));
3715 framer.ProcessInput("HTTP/1.1", 8);
3716 EXPECT_TRUE(framer.probable_http_response());
3717 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3718 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code());
3721 testing::StrictMock<test::MockVisitor> visitor;
3722 SpdyFramer framer(spdy_version_);
3723 framer.set_visitor(&visitor);
3725 EXPECT_CALL(visitor, OnError(_));
3726 framer.ProcessInput("HTTP/1.0", 8);
3727 EXPECT_TRUE(framer.probable_http_response());
3728 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3729 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code());
3733 TEST_P(SpdyFramerTest, DataFrameFlags) {
3734 for (int flags = 0; flags < 256; ++flags) {
3735 SCOPED_TRACE(testing::Message() << "Flags " << flags);
3737 testing::StrictMock<test::MockVisitor> visitor;
3738 SpdyFramer framer(spdy_version_);
3739 framer.set_visitor(&visitor);
3741 scoped_ptr<SpdyFrame> frame(
3742 framer.CreateDataFrame(1, "hello", 5, DATA_FLAG_NONE));
3743 SetFrameFlags(frame.get(), flags, spdy_version_);
3745 if (flags & ~DATA_FLAG_FIN) {
3746 EXPECT_CALL(visitor, OnError(_));
3747 } else {
3748 EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN));
3749 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false));
3750 if (flags & DATA_FLAG_FIN) {
3751 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
3755 framer.ProcessInput(frame->data(), frame->size());
3756 if (flags & ~DATA_FLAG_FIN) {
3757 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3758 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS,
3759 framer.error_code());
3760 } else {
3761 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3762 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3767 TEST_P(SpdyFramerTest, SynStreamFrameFlags) {
3768 for (int flags = 0; flags < 256; ++flags) {
3769 SCOPED_TRACE(testing::Message() << "Flags " << flags);
3771 testing::StrictMock<test::MockVisitor> visitor;
3772 SpdyFramer framer(spdy_version_);
3773 framer.set_visitor(&visitor);
3775 EXPECT_CALL(visitor, OnSynStreamCompressed(_, _));
3777 SpdyHeaderBlock headers;
3778 headers["foo"] = "bar";
3779 scoped_ptr<SpdyFrame> frame(
3780 framer.CreateSynStream(8, 3, 1, 0, CONTROL_FLAG_NONE, true, &headers));
3781 SetFrameFlags(frame.get(), flags, spdy_version_);
3783 if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
3784 EXPECT_CALL(visitor, OnError(_));
3785 } else {
3786 EXPECT_CALL(visitor, OnSynStream(8, 3, 1, 0, flags & CONTROL_FLAG_FIN,
3787 flags & CONTROL_FLAG_UNIDIRECTIONAL));
3788 EXPECT_CALL(visitor, OnControlFrameHeaderData(8, _, _))
3789 .WillRepeatedly(testing::Return(true));
3790 if (flags & DATA_FLAG_FIN) {
3791 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
3795 framer.ProcessInput(frame->data(), frame->size());
3796 if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
3797 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3798 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3799 framer.error_code());
3800 } else {
3801 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3802 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3807 TEST_P(SpdyFramerTest, SynReplyFrameFlags) {
3808 for (int flags = 0; flags < 256; ++flags) {
3809 SCOPED_TRACE(testing::Message() << "Flags " << flags);
3811 testing::StrictMock<test::MockVisitor> visitor;
3812 SpdyFramer framer(spdy_version_);
3813 framer.set_visitor(&visitor);
3815 SpdyHeaderBlock headers;
3816 headers["foo"] = "bar";
3817 scoped_ptr<SpdyFrame> frame(
3818 framer.CreateSynReply(37, CONTROL_FLAG_NONE, true, &headers));
3819 SetFrameFlags(frame.get(), flags, spdy_version_);
3821 if (flags & ~CONTROL_FLAG_FIN) {
3822 EXPECT_CALL(visitor, OnError(_));
3823 } else {
3824 EXPECT_CALL(visitor, OnSynReply(37, flags & CONTROL_FLAG_FIN));
3825 EXPECT_CALL(visitor, OnControlFrameHeaderData(37, _, _))
3826 .WillRepeatedly(testing::Return(true));
3827 if (flags & DATA_FLAG_FIN) {
3828 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
3832 framer.ProcessInput(frame->data(), frame->size());
3833 if (flags & ~CONTROL_FLAG_FIN) {
3834 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3835 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3836 framer.error_code());
3837 } else {
3838 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3839 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3844 TEST_P(SpdyFramerTest, RstStreamFrameFlags) {
3845 for (int flags = 0; flags < 256; ++flags) {
3846 SCOPED_TRACE(testing::Message() << "Flags " << flags);
3848 testing::StrictMock<test::MockVisitor> visitor;
3849 SpdyFramer framer(spdy_version_);
3850 framer.set_visitor(&visitor);
3852 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(13, RST_STREAM_CANCEL));
3853 SetFrameFlags(frame.get(), flags, spdy_version_);
3855 if (flags != 0) {
3856 EXPECT_CALL(visitor, OnError(_));
3857 } else {
3858 EXPECT_CALL(visitor, OnRstStream(13, RST_STREAM_CANCEL));
3861 framer.ProcessInput(frame->data(), frame->size());
3862 if (flags != 0) {
3863 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3864 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3865 framer.error_code());
3866 } else {
3867 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3868 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3873 TEST_P(SpdyFramerTest, SettingsFrameFlags) {
3874 for (int flags = 0; flags < 256; ++flags) {
3875 SCOPED_TRACE(testing::Message() << "Flags " << flags);
3877 testing::StrictMock<test::MockVisitor> visitor;
3878 SpdyFramer framer(spdy_version_);
3879 framer.set_visitor(&visitor);
3881 SettingsMap settings;
3882 settings[SETTINGS_UPLOAD_BANDWIDTH] =
3883 std::make_pair(SETTINGS_FLAG_NONE, 54321);
3884 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
3885 SetFrameFlags(frame.get(), flags, spdy_version_);
3887 if (flags & ~SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) {
3888 EXPECT_CALL(visitor, OnError(_));
3889 } else {
3890 EXPECT_CALL(visitor, OnSettings(
3891 flags & SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS));
3892 EXPECT_CALL(visitor, OnSetting(SETTINGS_UPLOAD_BANDWIDTH,
3893 SETTINGS_FLAG_NONE, 54321));
3896 framer.ProcessInput(frame->data(), frame->size());
3897 if (flags & ~SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) {
3898 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3899 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3900 framer.error_code());
3901 } else {
3902 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3903 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3908 TEST_P(SpdyFramerTest, GoawayFrameFlags) {
3909 for (int flags = 0; flags < 256; ++flags) {
3910 SCOPED_TRACE(testing::Message() << "Flags " << flags);
3912 testing::StrictMock<test::MockVisitor> visitor;
3913 SpdyFramer framer(spdy_version_);
3914 framer.set_visitor(&visitor);
3916 scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(97, GOAWAY_OK));
3917 SetFrameFlags(frame.get(), flags, spdy_version_);
3919 if (flags != 0) {
3920 EXPECT_CALL(visitor, OnError(_));
3921 } else {
3922 EXPECT_CALL(visitor, OnGoAway(97, GOAWAY_OK));
3925 framer.ProcessInput(frame->data(), frame->size());
3926 if (flags != 0) {
3927 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3928 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3929 framer.error_code());
3930 } else {
3931 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3932 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3937 TEST_P(SpdyFramerTest, HeadersFrameFlags) {
3938 for (int flags = 0; flags < 256; ++flags) {
3939 SCOPED_TRACE(testing::Message() << "Flags " << flags);
3941 testing::StrictMock<test::MockVisitor> visitor;
3942 SpdyFramer framer(spdy_version_);
3943 framer.set_visitor(&visitor);
3945 SpdyHeaderBlock headers;
3946 headers["foo"] = "bar";
3947 scoped_ptr<SpdyFrame> frame(
3948 framer.CreateHeaders(57, CONTROL_FLAG_NONE, true, &headers));
3949 SetFrameFlags(frame.get(), flags, spdy_version_);
3951 if (flags & ~CONTROL_FLAG_FIN) {
3952 EXPECT_CALL(visitor, OnError(_));
3953 } else {
3954 EXPECT_CALL(visitor, OnHeaders(57, flags & CONTROL_FLAG_FIN));
3955 EXPECT_CALL(visitor, OnControlFrameHeaderData(57, _, _))
3956 .WillRepeatedly(testing::Return(true));
3957 if (flags & DATA_FLAG_FIN) {
3958 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
3962 framer.ProcessInput(frame->data(), frame->size());
3963 if (flags & ~CONTROL_FLAG_FIN) {
3964 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3965 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3966 framer.error_code());
3967 } else {
3968 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3969 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3974 TEST_P(SpdyFramerTest, PingFrameFlags) {
3975 for (int flags = 0; flags < 256; ++flags) {
3976 SCOPED_TRACE(testing::Message() << "Flags " << flags);
3978 testing::StrictMock<test::MockVisitor> visitor;
3979 SpdyFramer framer(spdy_version_);
3980 framer.set_visitor(&visitor);
3982 scoped_ptr<SpdyFrame> frame(framer.CreatePingFrame(42));
3983 SetFrameFlags(frame.get(), flags, spdy_version_);
3985 if (flags != 0) {
3986 EXPECT_CALL(visitor, OnError(_));
3987 } else {
3988 EXPECT_CALL(visitor, OnPing(42));
3991 framer.ProcessInput(frame->data(), frame->size());
3992 if (flags != 0) {
3993 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3994 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3995 framer.error_code());
3996 } else {
3997 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3998 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4003 TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) {
4004 for (int flags = 0; flags < 256; ++flags) {
4005 SCOPED_TRACE(testing::Message() << "Flags " << flags);
4007 testing::StrictMock<test::MockVisitor> visitor;
4008 SpdyFramer framer(spdy_version_);
4009 framer.set_visitor(&visitor);
4011 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(4, 1024));
4012 SetFrameFlags(frame.get(), flags, spdy_version_);
4014 if (flags != 0) {
4015 EXPECT_CALL(visitor, OnError(_));
4016 } else {
4017 EXPECT_CALL(visitor, OnWindowUpdate(4, 1024));
4020 framer.ProcessInput(frame->data(), frame->size());
4021 if (flags != 0) {
4022 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
4023 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
4024 framer.error_code());
4025 } else {
4026 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4027 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4032 TEST_P(SpdyFramerTest, CredentialFrameFlags) {
4033 for (int flags = 0; flags < 256; ++flags) {
4034 SCOPED_TRACE(testing::Message() << "Flags " << flags);
4036 testing::StrictMock<test::MockVisitor> visitor;
4037 SpdyFramer framer(spdy_version_);
4038 framer.set_visitor(&visitor);
4040 SpdyCredential credential;
4041 scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential));
4042 SetFrameFlags(frame.get(), flags, spdy_version_);
4044 if (flags != 0) {
4045 EXPECT_CALL(visitor, OnError(_));
4046 } else {
4047 EXPECT_CALL(visitor, OnCredentialFrameData(_, _))
4048 .WillRepeatedly(testing::Return(true));
4051 framer.ProcessInput(frame->data(), frame->size());
4052 if (flags != 0) {
4053 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
4054 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
4055 framer.error_code());
4056 } else {
4057 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4058 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4063 TEST_P(SpdyFramerTest, EmptySynStream) {
4064 SpdyHeaderBlock headers;
4066 testing::StrictMock<test::MockVisitor> visitor;
4067 SpdyFramer framer(spdy_version_);
4068 framer.set_visitor(&visitor);
4070 EXPECT_CALL(visitor, OnSynStreamCompressed(_, _));
4071 scoped_ptr<SpdyFrame>
4072 frame(framer.CreateSynStream(1, 0, 1, 0, CONTROL_FLAG_NONE, true,
4073 &headers));
4074 // Adjust size to remove the name/value block.
4075 if (IsSpdy4()) {
4076 SetFrameLength(
4077 frame.get(),
4078 framer.GetSynStreamMinimumSize(),
4079 spdy_version_);
4080 } else {
4081 SetFrameLength(
4082 frame.get(),
4083 framer.GetSynStreamMinimumSize() - framer.GetControlFrameHeaderSize(),
4084 spdy_version_);
4087 EXPECT_CALL(visitor, OnSynStream(1, 0, 1, 0, false, false));
4088 EXPECT_CALL(visitor, OnControlFrameHeaderData(1, NULL, 0));
4090 framer.ProcessInput(frame->data(), framer.GetSynStreamMinimumSize());
4091 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4092 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4095 TEST_P(SpdyFramerTest, SettingsFlagsAndId) {
4096 const uint32 kId = 0x020304;
4097 const uint32 kFlags = 0x01;
4098 const uint32 kWireFormat = htonl(IsSpdy2() ? 0x04030201 : 0x01020304);
4100 SettingsFlagsAndId id_and_flags =
4101 SettingsFlagsAndId::FromWireFormat(spdy_version_, kWireFormat);
4102 EXPECT_EQ(kId, id_and_flags.id());
4103 EXPECT_EQ(kFlags, id_and_flags.flags());
4104 EXPECT_EQ(kWireFormat, id_and_flags.GetWireFormat(spdy_version_));
4107 // Test handling of a RST_STREAM with out-of-bounds status codes.
4108 TEST_P(SpdyFramerTest, RstStreamStatusBounds) {
4109 DCHECK_GE(0xff, RST_STREAM_NUM_STATUS_CODES);
4111 const unsigned char kV3RstStreamInvalid[] = {
4112 0x80, spdy_version_ch_, 0x00, 0x03,
4113 0x00, 0x00, 0x00, 0x08,
4114 0x00, 0x00, 0x00, 0x01,
4115 0x00, 0x00, 0x00, RST_STREAM_INVALID
4117 const unsigned char kV4RstStreamInvalid[] = {
4118 0x00, 0x0c, 0x03, 0x00,
4119 0x00, 0x00, 0x00, 0x01,
4120 0x00, 0x00, 0x00, RST_STREAM_INVALID
4123 const unsigned char kV3RstStreamNumStatusCodes[] = {
4124 0x80, spdy_version_ch_, 0x00, 0x03,
4125 0x00, 0x00, 0x00, 0x08,
4126 0x00, 0x00, 0x00, 0x01,
4127 0x00, 0x00, 0x00, RST_STREAM_NUM_STATUS_CODES
4129 const unsigned char kV4RstStreamNumStatusCodes[] = {
4130 0x00, 0x0c, 0x03, 0x00,
4131 0x00, 0x00, 0x00, 0x01,
4132 0x00, 0x00, 0x00, RST_STREAM_NUM_STATUS_CODES
4135 testing::StrictMock<test::MockVisitor> visitor;
4136 SpdyFramer framer(spdy_version_);
4137 framer.set_visitor(&visitor);
4139 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
4140 if (IsSpdy4()) {
4141 framer.ProcessInput(reinterpret_cast<const char*>(kV4RstStreamInvalid),
4142 arraysize(kV4RstStreamInvalid));
4143 } else {
4144 framer.ProcessInput(reinterpret_cast<const char*>(kV3RstStreamInvalid),
4145 arraysize(kV3RstStreamInvalid));
4147 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4148 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4150 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
4151 if (IsSpdy4()) {
4152 framer.ProcessInput(
4153 reinterpret_cast<const char*>(kV4RstStreamNumStatusCodes),
4154 arraysize(kV4RstStreamNumStatusCodes));
4155 } else {
4156 framer.ProcessInput(
4157 reinterpret_cast<const char*>(kV3RstStreamNumStatusCodes),
4158 arraysize(kV3RstStreamNumStatusCodes));
4160 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4161 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4164 // Tests handling of a GOAWAY frame with out-of-bounds stream ID.
4165 TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) {
4166 const unsigned char kV2FrameData[] = {
4167 0x80, spdy_version_ch_, 0x00, 0x07,
4168 0x00, 0x00, 0x00, 0x04,
4169 0xff, 0xff, 0xff, 0xff,
4171 const unsigned char kV3FrameData[] = {
4172 0x80, spdy_version_ch_, 0x00, 0x07,
4173 0x00, 0x00, 0x00, 0x08,
4174 0xff, 0xff, 0xff, 0xff,
4175 0x00, 0x00, 0x00, 0x00,
4177 const unsigned char kV4FrameData[] = {
4178 0x00, 0x10, 0x07, 0x00,
4179 0x00, 0x00, 0x00, 0x00,
4180 0xff, 0xff, 0xff, 0xff,
4181 0x00, 0x00, 0x00, 0x00,
4184 testing::StrictMock<test::MockVisitor> visitor;
4185 SpdyFramer framer(spdy_version_);
4186 framer.set_visitor(&visitor);
4188 EXPECT_CALL(visitor, OnGoAway(0x7fffffff, GOAWAY_OK));
4189 if (IsSpdy2()) {
4190 framer.ProcessInput(reinterpret_cast<const char*>(kV2FrameData),
4191 arraysize(kV2FrameData));
4192 } else if (IsSpdy3()) {
4193 framer.ProcessInput(reinterpret_cast<const char*>(kV3FrameData),
4194 arraysize(kV3FrameData));
4195 } else {
4196 framer.ProcessInput(reinterpret_cast<const char*>(kV4FrameData),
4197 arraysize(kV4FrameData));
4199 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4200 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4203 TEST_P(SpdyFramerTest, OnBlocked) {
4204 if (spdy_version_ < SPDY4) {
4205 return;
4208 const SpdyStreamId kStreamId = 0;
4210 testing::StrictMock<test::MockVisitor> visitor;
4211 SpdyFramer framer(spdy_version_);
4212 framer.set_visitor(&visitor);
4214 EXPECT_CALL(visitor, OnBlocked(kStreamId));
4216 SpdyBlockedIR blocked_ir(0);
4217 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeBlocked(blocked_ir));
4218 framer.ProcessInput(frame->data(), framer.GetBlockedSize());
4220 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4221 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4224 } // namespace net