Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / net / spdy / spdy_framer_test.cc
blob5e1163e701d64c4a2ffba90177a6987e8c8b01e3
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 "net/spdy/spdy_framer.h"
7 #include <stdlib.h>
8 #include <string.h>
10 #include <algorithm>
11 #include <limits>
12 #include <memory>
13 #include <string>
14 #include <vector>
16 #include "base/compiler_specific.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "net/spdy/hpack/hpack_constants.h"
19 #include "net/spdy/mock_spdy_framer_visitor.h"
20 #include "net/spdy/spdy_frame_builder.h"
21 #include "net/spdy/spdy_frame_reader.h"
22 #include "net/spdy/spdy_protocol.h"
23 #include "net/spdy/spdy_test_utils.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/platform_test.h"
27 using std::string;
28 using testing::_;
30 namespace net {
32 namespace test {
34 static const size_t kMaxDecompressedSize = 1024;
36 class MockDebugVisitor : public SpdyFramerDebugVisitorInterface {
37 public:
38 MOCK_METHOD4(OnSendCompressedFrame, void(SpdyStreamId stream_id,
39 SpdyFrameType type,
40 size_t payload_len,
41 size_t frame_len));
43 MOCK_METHOD3(OnReceiveCompressedFrame, void(SpdyStreamId stream_id,
44 SpdyFrameType type,
45 size_t frame_len));
48 class SpdyFramerTestUtil {
49 public:
50 // Decompress a single frame using the decompression context held by
51 // the SpdyFramer. The implemention is meant for use only in tests
52 // and will CHECK fail if the input is anything other than a single,
53 // well-formed compressed frame.
55 // Returns a new decompressed SpdyFrame.
56 template<class SpdyFrameType> static SpdyFrame* DecompressFrame(
57 SpdyFramer* framer, const SpdyFrameType& frame) {
58 DecompressionVisitor visitor(framer->protocol_version());
59 framer->set_visitor(&visitor);
60 CHECK_EQ(frame.size(), framer->ProcessInput(frame.data(), frame.size()));
61 CHECK_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer->state());
62 framer->set_visitor(NULL);
64 char* buffer = visitor.ReleaseBuffer();
65 CHECK(buffer != NULL);
66 SpdyFrame* decompressed_frame = new SpdyFrame(buffer, visitor.size(), true);
67 SetFrameLength(decompressed_frame,
68 visitor.size() - framer->GetControlFrameHeaderSize(),
69 framer->protocol_version());
70 return decompressed_frame;
73 class DecompressionVisitor : public SpdyFramerVisitorInterface {
74 public:
75 explicit DecompressionVisitor(SpdyMajorVersion version)
76 : version_(version), size_(0), finished_(false) {}
78 void ResetBuffer() {
79 CHECK(buffer_.get() == NULL);
80 CHECK_EQ(0u, size_);
81 CHECK(!finished_);
82 buffer_.reset(new char[kMaxDecompressedSize]);
85 void OnError(SpdyFramer* framer) override { LOG(FATAL); }
86 void OnDataFrameHeader(SpdyStreamId stream_id,
87 size_t length,
88 bool fin) override {
89 LOG(FATAL) << "Unexpected data frame header";
91 void OnStreamFrameData(SpdyStreamId stream_id,
92 const char* data,
93 size_t len,
94 bool fin) override {
95 LOG(FATAL);
98 void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {
99 LOG(FATAL);
102 bool OnControlFrameHeaderData(SpdyStreamId stream_id,
103 const char* header_data,
104 size_t len) override {
105 CHECK(buffer_.get() != NULL);
106 CHECK_GE(kMaxDecompressedSize, size_ + len);
107 CHECK(!finished_);
108 if (len != 0) {
109 memcpy(buffer_.get() + size_, header_data, len);
110 size_ += len;
111 } else {
112 // Done.
113 finished_ = true;
115 return true;
118 void OnSynStream(SpdyStreamId stream_id,
119 SpdyStreamId associated_stream_id,
120 SpdyPriority priority,
121 bool fin,
122 bool unidirectional) override {
123 SpdyFramer framer(version_);
124 framer.set_enable_compression(false);
125 SpdySynStreamIR syn_stream(stream_id);
126 syn_stream.set_associated_to_stream_id(associated_stream_id);
127 syn_stream.set_priority(priority);
128 syn_stream.set_fin(fin);
129 syn_stream.set_unidirectional(unidirectional);
130 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream));
131 ResetBuffer();
132 memcpy(buffer_.get(), frame->data(), framer.GetSynStreamMinimumSize());
133 size_ += framer.GetSynStreamMinimumSize();
136 void OnSynReply(SpdyStreamId stream_id, bool fin) override {
137 SpdyFramer framer(version_);
138 framer.set_enable_compression(false);
139 SpdyHeadersIR headers(stream_id);
140 headers.set_fin(fin);
141 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers));
142 ResetBuffer();
143 memcpy(buffer_.get(), frame->data(), framer.GetHeadersMinimumSize());
144 size_ += framer.GetSynStreamMinimumSize();
147 void OnRstStream(SpdyStreamId stream_id,
148 SpdyRstStreamStatus status) override {
149 LOG(FATAL);
151 void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) override {
152 LOG(FATAL);
154 void OnPing(SpdyPingId unique_id, bool is_ack) override { LOG(FATAL); }
155 void OnSettingsEnd() override { LOG(FATAL); }
156 void OnGoAway(SpdyStreamId last_accepted_stream_id,
157 SpdyGoAwayStatus status) override {
158 LOG(FATAL);
161 void OnHeaders(SpdyStreamId stream_id,
162 bool has_priority,
163 SpdyPriority priority,
164 SpdyStreamId parent_stream_id,
165 bool exclusive,
166 bool fin,
167 bool end) override {
168 SpdyFramer framer(version_);
169 framer.set_enable_compression(false);
170 SpdyHeadersIR headers(stream_id);
171 headers.set_has_priority(has_priority);
172 headers.set_priority(priority);
173 headers.set_parent_stream_id(parent_stream_id);
174 headers.set_exclusive(exclusive);
175 headers.set_fin(fin);
176 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers));
177 ResetBuffer();
178 memcpy(buffer_.get(), frame->data(), framer.GetHeadersMinimumSize());
179 size_ += framer.GetHeadersMinimumSize();
182 void OnWindowUpdate(SpdyStreamId stream_id,
183 int delta_window_size) override {
184 LOG(FATAL);
187 void OnPushPromise(SpdyStreamId stream_id,
188 SpdyStreamId promised_stream_id,
189 bool end) override {
190 SpdyFramer framer(version_);
191 framer.set_enable_compression(false);
192 SpdyPushPromiseIR push_promise(stream_id, promised_stream_id);
193 scoped_ptr<SpdyFrame> frame(framer.SerializePushPromise(push_promise));
194 ResetBuffer();
195 memcpy(buffer_.get(), frame->data(), framer.GetPushPromiseMinimumSize());
196 size_ += framer.GetPushPromiseMinimumSize();
199 void OnContinuation(SpdyStreamId stream_id, bool end) override {
200 LOG(FATAL);
203 void OnPriority(SpdyStreamId stream_id,
204 SpdyStreamId parent_stream_id,
205 uint8 weight,
206 bool exclusive) override {
207 // Do nothing.
210 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override {
211 LOG(FATAL);
212 return false;
215 char* ReleaseBuffer() {
216 CHECK(finished_);
217 return buffer_.release();
220 size_t size() const {
221 CHECK(finished_);
222 return size_;
225 private:
226 SpdyMajorVersion version_;
227 scoped_ptr<char[]> buffer_;
228 size_t size_;
229 bool finished_;
231 DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor);
234 private:
235 DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil);
238 class TestSpdyVisitor : public SpdyFramerVisitorInterface,
239 public SpdyFramerDebugVisitorInterface {
240 public:
241 // This is larger than our max frame size because header blocks that
242 // are too long can spill over into CONTINUATION frames.
243 static const size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024;
245 explicit TestSpdyVisitor(SpdyMajorVersion version)
246 : framer_(version),
247 use_compression_(false),
248 error_count_(0),
249 syn_frame_count_(0),
250 syn_reply_frame_count_(0),
251 headers_frame_count_(0),
252 push_promise_frame_count_(0),
253 goaway_count_(0),
254 setting_count_(0),
255 settings_ack_sent_(0),
256 settings_ack_received_(0),
257 continuation_count_(0),
258 altsvc_count_(0),
259 priority_count_(0),
260 test_altsvc_ir_(0),
261 on_unknown_frame_result_(false),
262 last_window_update_stream_(0),
263 last_window_update_delta_(0),
264 last_push_promise_stream_(0),
265 last_push_promise_promised_stream_(0),
266 data_bytes_(0),
267 fin_frame_count_(0),
268 fin_opaque_data_(),
269 fin_flag_count_(0),
270 zero_length_data_frame_count_(0),
271 control_frame_header_data_count_(0),
272 zero_length_control_frame_header_data_count_(0),
273 data_frame_count_(0),
274 last_payload_len_(0),
275 last_frame_len_(0),
276 header_buffer_(new char[kDefaultHeaderBufferSize]),
277 header_buffer_length_(0),
278 header_buffer_size_(kDefaultHeaderBufferSize),
279 header_stream_id_(static_cast<SpdyStreamId>(-1)),
280 header_control_type_(DATA),
281 header_buffer_valid_(false) {}
283 void OnError(SpdyFramer* f) override {
284 LOG(INFO) << "SpdyFramer Error: "
285 << SpdyFramer::ErrorCodeToString(f->error_code());
286 ++error_count_;
289 void OnDataFrameHeader(SpdyStreamId stream_id,
290 size_t length,
291 bool fin) override {
292 ++data_frame_count_;
293 header_stream_id_ = stream_id;
296 void OnStreamFrameData(SpdyStreamId stream_id,
297 const char* data,
298 size_t len,
299 bool fin) override {
300 EXPECT_EQ(header_stream_id_, stream_id);
301 if (len == 0) {
302 ++zero_length_data_frame_count_;
305 data_bytes_ += len;
306 LOG(INFO) << "OnStreamFrameData(" << stream_id << ", \"";
307 if (len > 0) {
308 for (size_t i = 0 ; i < len; ++i) {
309 LOG(INFO) << std::hex << (0xFF & static_cast<unsigned int>(data[i]))
310 << std::dec;
313 LOG(INFO) << "\", " << len << ")\n";
316 void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {
317 EXPECT_EQ(header_stream_id_, stream_id);
318 data_bytes_ += len;
319 LOG(INFO) << "OnStreamPadding(" << stream_id << ", " << len << ")\n";
322 bool OnControlFrameHeaderData(SpdyStreamId stream_id,
323 const char* header_data,
324 size_t len) override {
325 ++control_frame_header_data_count_;
326 CHECK_EQ(header_stream_id_, stream_id);
327 if (len == 0) {
328 ++zero_length_control_frame_header_data_count_;
329 // Indicates end-of-header-block.
330 headers_.clear();
331 CHECK(header_buffer_valid_);
332 size_t parsed_length = framer_.ParseHeaderBlockInBuffer(
333 header_buffer_.get(), header_buffer_length_, &headers_);
334 LOG_IF(DFATAL, header_buffer_length_ != parsed_length)
335 << "Check failed: header_buffer_length_ == parsed_length "
336 << "(" << header_buffer_length_ << " vs. " << parsed_length << ")";
337 return true;
339 const size_t available = header_buffer_size_ - header_buffer_length_;
340 if (len > available) {
341 header_buffer_valid_ = false;
342 return false;
344 memcpy(header_buffer_.get() + header_buffer_length_, header_data, len);
345 header_buffer_length_ += len;
346 return true;
349 void OnSynStream(SpdyStreamId stream_id,
350 SpdyStreamId associated_stream_id,
351 SpdyPriority priority,
352 bool fin,
353 bool unidirectional) override {
354 ++syn_frame_count_;
355 if (framer_.protocol_version() > SPDY3) {
356 InitHeaderStreaming(HEADERS, stream_id);
357 } else {
358 InitHeaderStreaming(SYN_STREAM, stream_id);
360 if (fin) {
361 ++fin_flag_count_;
365 void OnSynReply(SpdyStreamId stream_id, bool fin) override {
366 ++syn_reply_frame_count_;
367 if (framer_.protocol_version() > SPDY3) {
368 InitHeaderStreaming(HEADERS, stream_id);
369 } else {
370 InitHeaderStreaming(SYN_REPLY, stream_id);
372 if (fin) {
373 ++fin_flag_count_;
377 void OnRstStream(SpdyStreamId stream_id,
378 SpdyRstStreamStatus status) override {
379 ++fin_frame_count_;
382 bool OnRstStreamFrameData(const char* rst_stream_data, size_t len) override {
383 if ((rst_stream_data != NULL) && (len > 0)) {
384 fin_opaque_data_ += string(rst_stream_data, len);
386 return true;
389 void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) override {
390 ++setting_count_;
393 void OnSettingsAck() override {
394 DCHECK_LT(SPDY3, framer_.protocol_version());
395 ++settings_ack_received_;
398 void OnSettingsEnd() override {
399 if (framer_.protocol_version() <= SPDY3) { return; }
400 ++settings_ack_sent_;
403 void OnPing(SpdyPingId unique_id, bool is_ack) override { DLOG(FATAL); }
405 void OnGoAway(SpdyStreamId last_accepted_stream_id,
406 SpdyGoAwayStatus status) override {
407 ++goaway_count_;
410 void OnHeaders(SpdyStreamId stream_id,
411 bool has_priority,
412 SpdyPriority priority,
413 SpdyStreamId parent_stream_id,
414 bool exclusive,
415 bool fin,
416 bool end) override {
417 ++headers_frame_count_;
418 InitHeaderStreaming(HEADERS, stream_id);
419 if (fin) {
420 ++fin_flag_count_;
422 header_has_priority_ = has_priority;
423 header_parent_stream_id_ = parent_stream_id;
424 header_exclusive_ = exclusive;
427 void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {
428 last_window_update_stream_ = stream_id;
429 last_window_update_delta_ = delta_window_size;
432 void OnPushPromise(SpdyStreamId stream_id,
433 SpdyStreamId promised_stream_id,
434 bool end) override {
435 ++push_promise_frame_count_;
436 InitHeaderStreaming(PUSH_PROMISE, stream_id);
437 last_push_promise_stream_ = stream_id;
438 last_push_promise_promised_stream_ = promised_stream_id;
441 void OnContinuation(SpdyStreamId stream_id, bool end) override {
442 ++continuation_count_;
445 void OnAltSvc(SpdyStreamId stream_id,
446 StringPiece origin,
447 const SpdyAltSvcWireFormat::AlternativeServiceVector&
448 altsvc_vector) override {
449 test_altsvc_ir_.set_stream_id(stream_id);
450 if (origin.length() > 0) {
451 test_altsvc_ir_.set_origin(origin.as_string());
453 for (const SpdyAltSvcWireFormat::AlternativeService& altsvc :
454 altsvc_vector) {
455 test_altsvc_ir_.add_altsvc(altsvc);
457 ++altsvc_count_;
460 void OnPriority(SpdyStreamId stream_id,
461 SpdyStreamId parent_stream_id,
462 uint8 weight,
463 bool exclusive) override {
464 ++priority_count_;
467 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override {
468 DLOG(INFO) << "Unknown frame type " << frame_type;
469 return on_unknown_frame_result_;
472 void OnSendCompressedFrame(SpdyStreamId stream_id,
473 SpdyFrameType type,
474 size_t payload_len,
475 size_t frame_len) override {
476 last_payload_len_ = payload_len;
477 last_frame_len_ = frame_len;
480 void OnReceiveCompressedFrame(SpdyStreamId stream_id,
481 SpdyFrameType type,
482 size_t frame_len) override {
483 last_frame_len_ = frame_len;
486 // Convenience function which runs a framer simulation with particular input.
487 void SimulateInFramer(const unsigned char* input, size_t size) {
488 framer_.set_enable_compression(use_compression_);
489 framer_.set_visitor(this);
490 size_t input_remaining = size;
491 const char* input_ptr = reinterpret_cast<const char*>(input);
492 while (input_remaining > 0 &&
493 framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) {
494 // To make the tests more interesting, we feed random (and small) chunks
495 // into the framer. This simulates getting strange-sized reads from
496 // the socket.
497 const size_t kMaxReadSize = 32;
498 size_t bytes_read =
499 (rand() % std::min(input_remaining, kMaxReadSize)) + 1;
500 size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read);
501 input_remaining -= bytes_processed;
502 input_ptr += bytes_processed;
506 void InitHeaderStreaming(SpdyFrameType header_control_type,
507 SpdyStreamId stream_id) {
508 if (!SpdyConstants::IsValidFrameType(framer_.protocol_version(),
509 SpdyConstants::SerializeFrameType(framer_.protocol_version(),
510 header_control_type))) {
511 DLOG(FATAL) << "Attempted to init header streaming with "
512 << "invalid control frame type: "
513 << header_control_type;
515 memset(header_buffer_.get(), 0, header_buffer_size_);
516 header_buffer_length_ = 0;
517 header_stream_id_ = stream_id;
518 header_control_type_ = header_control_type;
519 header_buffer_valid_ = true;
520 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
523 // Override the default buffer size (16K). Call before using the framer!
524 void set_header_buffer_size(size_t header_buffer_size) {
525 header_buffer_size_ = header_buffer_size;
526 header_buffer_.reset(new char[header_buffer_size]);
529 // Largest control frame that the SPDY implementation sends, including the
530 // size of the header.
531 static size_t sent_control_frame_max_size() {
532 return SpdyFramer::kMaxControlFrameSize;
535 static size_t header_data_chunk_max_size() {
536 return SpdyFramer::kHeaderDataChunkMaxSize;
539 SpdyFramer framer_;
540 bool use_compression_;
542 // Counters from the visitor callbacks.
543 int error_count_;
544 int syn_frame_count_;
545 int syn_reply_frame_count_;
546 int headers_frame_count_;
547 int push_promise_frame_count_;
548 int goaway_count_;
549 int setting_count_;
550 int settings_ack_sent_;
551 int settings_ack_received_;
552 int continuation_count_;
553 int altsvc_count_;
554 int priority_count_;
555 SpdyAltSvcIR test_altsvc_ir_;
556 bool on_unknown_frame_result_;
557 SpdyStreamId last_window_update_stream_;
558 int last_window_update_delta_;
559 SpdyStreamId last_push_promise_stream_;
560 SpdyStreamId last_push_promise_promised_stream_;
561 int data_bytes_;
562 int fin_frame_count_; // The count of RST_STREAM type frames received.
563 string fin_opaque_data_;
564 int fin_flag_count_; // The count of frames with the FIN flag set.
565 int zero_length_data_frame_count_; // The count of zero-length data frames.
566 int control_frame_header_data_count_; // The count of chunks received.
567 // The count of zero-length control frame header data chunks received.
568 int zero_length_control_frame_header_data_count_;
569 int data_frame_count_;
570 size_t last_payload_len_;
571 size_t last_frame_len_;
573 // Header block streaming state:
574 scoped_ptr<char[]> header_buffer_;
575 size_t header_buffer_length_;
576 size_t header_buffer_size_;
577 SpdyStreamId header_stream_id_;
578 SpdyFrameType header_control_type_;
579 bool header_buffer_valid_;
580 SpdyHeaderBlock headers_;
581 bool header_has_priority_;
582 SpdyStreamId header_parent_stream_id_;
583 bool header_exclusive_;
586 class SpdyFramerPeer {
587 public:
588 static size_t ControlFrameBufferSize() {
589 return SpdyFramer::kControlFrameBufferSize;
591 static size_t GetNumberRequiredContinuationFrames(SpdyFramer* framer,
592 size_t size) {
593 return framer->GetNumberRequiredContinuationFrames(size);
597 // Retrieves serialized headers from a HEADERS or SYN_STREAM frame.
598 base::StringPiece GetSerializedHeaders(const SpdyFrame* frame,
599 const SpdyFramer& framer) {
600 SpdyFrameReader reader(frame->data(), frame->size());
601 if (framer.protocol_version() > SPDY3) {
602 reader.Seek(3); // Seek past the frame length.
603 } else {
604 reader.Seek(2); // Seek past the frame length.
606 SpdyFrameType frame_type;
607 if (framer.protocol_version() > SPDY3) {
608 uint8 serialized_type;
609 reader.ReadUInt8(&serialized_type);
610 frame_type = SpdyConstants::ParseFrameType(framer.protocol_version(),
611 serialized_type);
612 DCHECK_EQ(HEADERS, frame_type);
613 uint8 flags;
614 reader.ReadUInt8(&flags);
615 if (flags & HEADERS_FLAG_PRIORITY) {
616 frame_type = SYN_STREAM;
618 } else {
619 uint16 serialized_type;
620 reader.ReadUInt16(&serialized_type);
621 frame_type = SpdyConstants::ParseFrameType(framer.protocol_version(),
622 serialized_type);
623 DCHECK(frame_type == HEADERS ||
624 frame_type == SYN_STREAM) << frame_type;
627 if (frame_type == SYN_STREAM) {
628 return StringPiece(frame->data() + framer.GetSynStreamMinimumSize(),
629 frame->size() - framer.GetSynStreamMinimumSize());
630 } else {
631 return StringPiece(frame->data() + framer.GetHeadersMinimumSize(),
632 frame->size() - framer.GetHeadersMinimumSize());
636 class SpdyFramerTest : public ::testing::TestWithParam<SpdyMajorVersion> {
637 protected:
638 void SetUp() override {
639 spdy_version_ = GetParam();
640 spdy_version_ch_ = static_cast<unsigned char>(
641 SpdyConstants::SerializeMajorVersion(spdy_version_));
644 void CompareFrame(const string& description,
645 const SpdyFrame& actual_frame,
646 const unsigned char* expected,
647 const int expected_len) {
648 const unsigned char* actual =
649 reinterpret_cast<const unsigned char*>(actual_frame.data());
650 CompareCharArraysWithHexError(
651 description, actual, actual_frame.size(), expected, expected_len);
654 void CompareFrames(const string& description,
655 const SpdyFrame& expected_frame,
656 const SpdyFrame& actual_frame) {
657 CompareCharArraysWithHexError(
658 description,
659 reinterpret_cast<const unsigned char*>(expected_frame.data()),
660 expected_frame.size(),
661 reinterpret_cast<const unsigned char*>(actual_frame.data()),
662 actual_frame.size());
665 // Returns true if the two header blocks have equivalent content.
666 bool CompareHeaderBlocks(const SpdyHeaderBlock* expected,
667 const SpdyHeaderBlock* actual) {
668 if (expected->size() != actual->size()) {
669 LOG(ERROR) << "Expected " << expected->size() << " headers; actually got "
670 << actual->size() << ".";
671 return false;
673 for (SpdyHeaderBlock::const_iterator it = expected->begin();
674 it != expected->end();
675 ++it) {
676 SpdyHeaderBlock::const_iterator it2 = actual->find(it->first);
677 if (it2 == actual->end()) {
678 LOG(ERROR) << "Expected header name '" << it->first << "'.";
679 return false;
681 if (it->second.compare(it2->second) != 0) {
682 LOG(ERROR) << "Expected header named '" << it->first
683 << "' to have a value of '" << it->second
684 << "'. The actual value received was '" << it2->second
685 << "'.";
686 return false;
689 return true;
692 bool IsSpdy2() { return spdy_version_ == SPDY2; }
693 bool IsSpdy3() { return spdy_version_ == SPDY3; }
694 bool IsHttp2() { return spdy_version_ == HTTP2; }
696 // Version of SPDY protocol to be used.
697 SpdyMajorVersion spdy_version_;
698 unsigned char spdy_version_ch_;
701 // All tests are run with 3 different SPDY versions: SPDY/2, SPDY/3, HTTP/2.
702 INSTANTIATE_TEST_CASE_P(SpdyFramerTests,
703 SpdyFramerTest,
704 ::testing::Values(SPDY2, SPDY3, HTTP2));
706 // Test that we ignore cookie where both name and value are empty.
707 TEST_P(SpdyFramerTest, HeaderBlockWithEmptyCookie) {
708 if (spdy_version_ > SPDY3) {
709 // Not implemented for hpack.
710 return;
713 SpdyFramer framer(spdy_version_);
714 framer.set_enable_compression(true);
715 SpdyHeadersIR headers(1);
716 headers.set_priority(1);
717 headers.SetHeader("cookie",
718 "=; key=value; ; = ; foo; bar=; ; = ; k2=v2 ; =");
719 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers));
720 EXPECT_TRUE(frame.get() != NULL);
722 TestSpdyVisitor visitor(spdy_version_);
723 visitor.use_compression_ = true;
724 visitor.SimulateInFramer(
725 reinterpret_cast<unsigned char*>(frame->data()),
726 frame->size());
728 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
729 EXPECT_FALSE(CompareHeaderBlocks(&headers.header_block(), &visitor.headers_));
730 EXPECT_EQ(1u, visitor.headers_.size());
731 EXPECT_EQ("key=value; foo; bar=; k2=v2 ", visitor.headers_["cookie"]);
734 // Test that we can encode and decode a SpdyHeaderBlock in serialized form.
735 TEST_P(SpdyFramerTest, HeaderBlockInBuffer) {
736 SpdyFramer framer(spdy_version_);
737 framer.set_enable_compression(false);
739 // Encode the header block into a Headers frame.
740 SpdyHeadersIR headers(1);
741 headers.set_priority(1);
742 headers.SetHeader("alpha", "beta");
743 headers.SetHeader("gamma", "charlie");
744 headers.SetHeader("cookie", "key1=value1; key2=value2");
745 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers));
746 EXPECT_TRUE(frame.get() != NULL);
748 TestSpdyVisitor visitor(spdy_version_);
749 visitor.use_compression_ = false;
750 visitor.SimulateInFramer(
751 reinterpret_cast<unsigned char*>(frame->data()),
752 frame->size());
754 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
755 EXPECT_TRUE(CompareHeaderBlocks(&headers.header_block(), &visitor.headers_));
758 // Test that if there's not a full frame, we fail to parse it.
759 TEST_P(SpdyFramerTest, UndersizedHeaderBlockInBuffer) {
760 SpdyFramer framer(spdy_version_);
761 framer.set_enable_compression(false);
763 // Encode the header block into a Headers frame.
764 SpdyHeadersIR headers(1);
765 headers.set_priority(1);
766 headers.SetHeader("alpha", "beta");
767 headers.SetHeader("gamma", "charlie");
768 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers));
769 EXPECT_TRUE(frame.get() != NULL);
771 TestSpdyVisitor visitor(spdy_version_);
772 visitor.use_compression_ = false;
773 visitor.SimulateInFramer(
774 reinterpret_cast<unsigned char*>(frame->data()),
775 frame->size() - 2);
777 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
778 EXPECT_EQ(0u, visitor.headers_.size());
781 // Test that we can encode and decode stream dependency values in a header
782 // frame.
783 TEST_P(SpdyFramerTest, HeaderStreamDependencyValues) {
784 if (spdy_version_ <= SPDY3) {
785 return;
787 SpdyFramer framer(spdy_version_);
788 framer.set_enable_compression(false);
790 const SpdyStreamId parent_stream_id_test_array[] = {0, 3};
791 for (SpdyStreamId parent_stream_id : parent_stream_id_test_array) {
792 const bool exclusive_test_array[] = {true, false};
793 for (bool exclusive : exclusive_test_array) {
794 SpdyHeadersIR headers(1);
795 headers.set_has_priority(true);
796 headers.set_parent_stream_id(parent_stream_id);
797 headers.set_exclusive(exclusive);
798 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers));
799 EXPECT_TRUE(frame.get() != NULL);
801 TestSpdyVisitor visitor(spdy_version_);
802 visitor.use_compression_ = false;
803 visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame->data()),
804 frame->size());
806 EXPECT_TRUE(visitor.header_has_priority_);
807 EXPECT_EQ(parent_stream_id, visitor.header_parent_stream_id_);
808 EXPECT_EQ(exclusive, visitor.header_exclusive_);
813 // Test that if we receive a SYN_REPLY with stream ID zero, we signal an error
814 // (but don't crash).
815 TEST_P(SpdyFramerTest, SynReplyWithStreamIdZero) {
816 if (spdy_version_ > SPDY3) {
817 return;
819 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
820 SpdyFramer framer(spdy_version_);
821 framer.set_visitor(&visitor);
823 SpdySynReplyIR syn_reply(0);
824 syn_reply.SetHeader("alpha", "beta");
825 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeSynReply(syn_reply));
826 ASSERT_TRUE(frame.get() != NULL);
828 // We shouldn't have to read the whole frame before we signal an error.
829 EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
830 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size()));
831 EXPECT_TRUE(framer.HasError());
832 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code())
833 << SpdyFramer::ErrorCodeToString(framer.error_code());
836 // Test that if we receive a HEADERS with stream ID zero, we signal an error
837 // (but don't crash).
838 TEST_P(SpdyFramerTest, HeadersWithStreamIdZero) {
839 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
840 SpdyFramer framer(spdy_version_);
841 framer.set_visitor(&visitor);
843 SpdyHeadersIR headers_ir(0);
844 headers_ir.SetHeader("alpha", "beta");
845 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeHeaders(headers_ir));
846 ASSERT_TRUE(frame.get() != NULL);
848 // We shouldn't have to read the whole frame before we signal an error.
849 EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
850 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size()));
851 EXPECT_TRUE(framer.HasError());
852 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code())
853 << SpdyFramer::ErrorCodeToString(framer.error_code());
856 // Test that if we receive a PUSH_PROMISE with stream ID zero, we signal an
857 // error (but don't crash).
858 TEST_P(SpdyFramerTest, PushPromiseWithStreamIdZero) {
859 if (spdy_version_ <= SPDY3) {
860 return;
863 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
864 SpdyFramer framer(spdy_version_);
865 framer.set_visitor(&visitor);
867 SpdyPushPromiseIR push_promise(0, 4);
868 push_promise.SetHeader("alpha", "beta");
869 scoped_ptr<SpdySerializedFrame> frame(
870 framer.SerializePushPromise(push_promise));
871 ASSERT_TRUE(frame.get() != NULL);
873 // We shouldn't have to read the whole frame before we signal an error.
874 EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
875 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size()));
876 EXPECT_TRUE(framer.HasError());
877 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code())
878 << SpdyFramer::ErrorCodeToString(framer.error_code());
881 // Test that if we receive a PUSH_PROMISE with promised stream ID zero, we
882 // signal an error (but don't crash).
883 TEST_P(SpdyFramerTest, PushPromiseWithPromisedStreamIdZero) {
884 if (spdy_version_ <= SPDY3) {
885 return;
888 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
889 SpdyFramer framer(spdy_version_);
890 framer.set_visitor(&visitor);
892 SpdyPushPromiseIR push_promise(3, 0);
893 push_promise.SetHeader("alpha", "beta");
894 scoped_ptr<SpdySerializedFrame> frame(
895 framer.SerializePushPromise(push_promise));
896 ASSERT_TRUE(frame.get() != NULL);
898 // We shouldn't have to read the whole frame before we signal an error.
899 EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
900 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size()));
901 EXPECT_TRUE(framer.HasError());
902 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code())
903 << SpdyFramer::ErrorCodeToString(framer.error_code());
906 TEST_P(SpdyFramerTest, DuplicateHeader) {
907 if (spdy_version_ > SPDY3) {
908 // TODO(jgraettinger): Punting on this because we haven't determined
909 // whether duplicate HPACK headers other than Cookie are an error.
910 // If they are, this will need to be updated to use HpackOutputStream.
911 return;
913 SpdyFramer framer(spdy_version_);
914 // Frame builder with plentiful buffer size.
915 SpdyFrameBuilder frame(1024, spdy_version_);
916 if (spdy_version_ <= SPDY3) {
917 frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
918 frame.WriteUInt32(3); // stream_id
919 frame.WriteUInt32(0); // associated stream id
920 frame.WriteUInt16(0); // Priority.
921 } else {
922 frame.BeginNewFrame(framer, HEADERS, HEADERS_FLAG_PRIORITY, 3);
923 frame.WriteUInt32(framer.GetHighestPriority());
926 if (IsSpdy2()) {
927 frame.WriteUInt16(2); // Number of headers.
928 frame.WriteStringPiece16("name");
929 frame.WriteStringPiece16("value1");
930 frame.WriteStringPiece16("name");
931 frame.WriteStringPiece16("value2");
932 } else {
933 frame.WriteUInt32(2); // Number of headers.
934 frame.WriteStringPiece32("name");
935 frame.WriteStringPiece32("value1");
936 frame.WriteStringPiece32("name");
937 frame.WriteStringPiece32("value2");
939 // write the length
940 frame.RewriteLength(framer);
942 SpdyHeaderBlock new_headers;
943 framer.set_enable_compression(false);
944 scoped_ptr<SpdyFrame> control_frame(frame.take());
945 base::StringPiece serialized_headers =
946 GetSerializedHeaders(control_frame.get(), framer);
947 // This should fail because duplicate headers are verboten by the spec.
948 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
949 serialized_headers.size(),
950 &new_headers));
953 TEST_P(SpdyFramerTest, MultiValueHeader) {
954 SpdyFramer framer(spdy_version_);
955 // Frame builder with plentiful buffer size.
956 SpdyFrameBuilder frame(1024, spdy_version_);
957 if (spdy_version_ <= SPDY3) {
958 frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
959 frame.WriteUInt32(3); // stream_id
960 frame.WriteUInt32(0); // associated stream id
961 frame.WriteUInt16(0); // Priority.
962 } else {
963 frame.BeginNewFrame(framer,
964 HEADERS,
965 HEADERS_FLAG_PRIORITY | HEADERS_FLAG_END_HEADERS,
967 frame.WriteUInt32(0); // Priority exclusivity and dependent stream.
968 frame.WriteUInt8(255); // Priority weight.
971 string value("value1\0value2", 13);
972 if (IsSpdy2()) {
973 frame.WriteUInt16(1); // Number of headers.
974 frame.WriteStringPiece16("name");
975 frame.WriteStringPiece16(value);
976 } else if (spdy_version_ > SPDY3) {
977 // TODO(jgraettinger): If this pattern appears again, move to test class.
978 SpdyHeaderBlock header_set;
979 header_set["name"] = value;
980 string buffer;
981 HpackEncoder encoder(ObtainHpackHuffmanTable());
982 encoder.EncodeHeaderSetWithoutCompression(header_set, &buffer);
983 frame.WriteBytes(&buffer[0], buffer.size());
984 } else {
985 frame.WriteUInt32(1); // Number of headers.
986 frame.WriteStringPiece32("name");
987 frame.WriteStringPiece32(value);
989 // write the length
990 frame.RewriteLength(framer);
992 framer.set_enable_compression(false);
993 scoped_ptr<SpdyFrame> control_frame(frame.take());
995 TestSpdyVisitor visitor(spdy_version_);
996 visitor.use_compression_ = false;
997 visitor.SimulateInFramer(
998 reinterpret_cast<unsigned char*>(control_frame->data()),
999 control_frame->size());
1001 EXPECT_THAT(visitor.headers_,
1002 testing::ElementsAre(testing::Pair("name", value)));
1005 TEST_P(SpdyFramerTest, BasicCompression) {
1006 if (spdy_version_ > SPDY3) {
1007 // Deflate compression doesn't apply to HPACK.
1008 return;
1010 scoped_ptr<TestSpdyVisitor> visitor(new TestSpdyVisitor(spdy_version_));
1011 SpdyFramer framer(spdy_version_);
1012 framer.set_debug_visitor(visitor.get());
1013 SpdySynStreamIR syn_stream(1);
1014 syn_stream.set_priority(1);
1015 syn_stream.SetHeader("server", "SpdyServer 1.0");
1016 syn_stream.SetHeader("date", "Mon 12 Jan 2009 12:12:12 PST");
1017 syn_stream.SetHeader("status", "200");
1018 syn_stream.SetHeader("version", "HTTP/1.1");
1019 syn_stream.SetHeader("content-type", "text/html");
1020 syn_stream.SetHeader("content-length", "12");
1021 scoped_ptr<SpdyFrame> frame1(framer.SerializeSynStream(syn_stream));
1022 size_t uncompressed_size1 = visitor->last_payload_len_;
1023 size_t compressed_size1 =
1024 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize();
1025 if (IsSpdy2()) {
1026 EXPECT_EQ(139u, uncompressed_size1);
1027 #if defined(USE_SYSTEM_ZLIB)
1028 EXPECT_EQ(155u, compressed_size1);
1029 #else // !defined(USE_SYSTEM_ZLIB)
1030 EXPECT_EQ(135u, compressed_size1);
1031 #endif // !defined(USE_SYSTEM_ZLIB)
1032 } else {
1033 EXPECT_EQ(165u, uncompressed_size1);
1034 #if defined(USE_SYSTEM_ZLIB)
1035 EXPECT_EQ(181u, compressed_size1);
1036 #else // !defined(USE_SYSTEM_ZLIB)
1037 EXPECT_EQ(117u, compressed_size1);
1038 #endif // !defined(USE_SYSTEM_ZLIB)
1040 scoped_ptr<SpdyFrame> frame2(framer.SerializeSynStream(syn_stream));
1041 size_t uncompressed_size2 = visitor->last_payload_len_;
1042 size_t compressed_size2 =
1043 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize();
1045 // Expect the second frame to be more compact than the first.
1046 EXPECT_LE(frame2->size(), frame1->size());
1048 // Decompress the first frame
1049 scoped_ptr<SpdyFrame> frame3(
1050 SpdyFramerTestUtil::DecompressFrame(&framer, *frame1));
1052 // Decompress the second frame
1053 visitor.reset(new TestSpdyVisitor(spdy_version_));
1054 framer.set_debug_visitor(visitor.get());
1055 scoped_ptr<SpdyFrame> frame4(
1056 SpdyFramerTestUtil::DecompressFrame(&framer, *frame2));
1057 size_t uncompressed_size4 =
1058 frame4->size() - framer.GetSynStreamMinimumSize();
1059 size_t compressed_size4 =
1060 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize();
1061 if (IsSpdy2()) {
1062 EXPECT_EQ(139u, uncompressed_size4);
1063 #if defined(USE_SYSTEM_ZLIB)
1064 EXPECT_EQ(149u, compressed_size4);
1065 #else // !defined(USE_SYSTEM_ZLIB)
1066 EXPECT_EQ(101u, compressed_size4);
1067 #endif // !defined(USE_SYSTEM_ZLIB)
1068 } else {
1069 EXPECT_EQ(165u, uncompressed_size4);
1070 #if defined(USE_SYSTEM_ZLIB)
1071 EXPECT_EQ(175u, compressed_size4);
1072 #else // !defined(USE_SYSTEM_ZLIB)
1073 EXPECT_EQ(102u, compressed_size4);
1074 #endif // !defined(USE_SYSTEM_ZLIB)
1077 EXPECT_EQ(uncompressed_size1, uncompressed_size2);
1078 EXPECT_EQ(uncompressed_size1, uncompressed_size4);
1079 EXPECT_EQ(compressed_size2, compressed_size4);
1081 // Expect frames 3 & 4 to be the same.
1082 CompareFrames("Uncompressed SYN_STREAM", *frame3, *frame4);
1084 // Expect frames 3 to be the same as a uncompressed frame created
1085 // from scratch.
1086 framer.set_enable_compression(false);
1087 scoped_ptr<SpdyFrame> uncompressed_frame(
1088 framer.SerializeSynStream(syn_stream));
1089 CompareFrames("Uncompressed SYN_STREAM", *frame3, *uncompressed_frame);
1092 TEST_P(SpdyFramerTest, CompressEmptyHeaders) {
1093 // See crbug.com/172383
1094 SpdyHeadersIR headers(1);
1095 headers.SetHeader("server", "SpdyServer 1.0");
1096 headers.SetHeader("date", "Mon 12 Jan 2009 12:12:12 PST");
1097 headers.SetHeader("status", "200");
1098 headers.SetHeader("version", "HTTP/1.1");
1099 headers.SetHeader("content-type", "text/html");
1100 headers.SetHeader("content-length", "12");
1101 headers.SetHeader("x-empty-header", "");
1103 SpdyFramer framer(spdy_version_);
1104 framer.set_enable_compression(true);
1105 scoped_ptr<SpdyFrame> frame1(framer.SerializeHeaders(headers));
1108 TEST_P(SpdyFramerTest, Basic) {
1109 const unsigned char kV2Input[] = {
1110 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1
1111 0x00, 0x00, 0x00, 0x14,
1112 0x00, 0x00, 0x00, 0x01,
1113 0x00, 0x00, 0x00, 0x00,
1114 0x00, 0x00, 0x00, 0x01,
1115 0x00, 0x02, 'h', 'h',
1116 0x00, 0x02, 'v', 'v',
1118 0x80, spdy_version_ch_, 0x00, 0x08, // HEADERS on Stream #1
1119 0x00, 0x00, 0x00, 0x18,
1120 0x00, 0x00, 0x00, 0x01,
1121 0x00, 0x00, 0x00, 0x02,
1122 0x00, 0x02, 'h', '2',
1123 0x00, 0x02, 'v', '2',
1124 0x00, 0x02, 'h', '3',
1125 0x00, 0x02, 'v', '3',
1127 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1128 0x00, 0x00, 0x00, 0x0c,
1129 0xde, 0xad, 0xbe, 0xef,
1130 0xde, 0xad, 0xbe, 0xef,
1131 0xde, 0xad, 0xbe, 0xef,
1133 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #3
1134 0x00, 0x00, 0x00, 0x0c,
1135 0x00, 0x00, 0x00, 0x03,
1136 0x00, 0x00, 0x00, 0x00,
1137 0x00, 0x00, 0x00, 0x00,
1139 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
1140 0x00, 0x00, 0x00, 0x08,
1141 0xde, 0xad, 0xbe, 0xef,
1142 0xde, 0xad, 0xbe, 0xef,
1144 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1145 0x00, 0x00, 0x00, 0x04,
1146 0xde, 0xad, 0xbe, 0xef,
1148 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #1
1149 0x00, 0x00, 0x00, 0x08,
1150 0x00, 0x00, 0x00, 0x01,
1151 0x00, 0x00, 0x00, 0x05, // RST_STREAM_CANCEL
1153 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
1154 0x00, 0x00, 0x00, 0x00,
1156 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #3
1157 0x00, 0x00, 0x00, 0x08,
1158 0x00, 0x00, 0x00, 0x03,
1159 0x00, 0x00, 0x00, 0x05, // RST_STREAM_CANCEL
1162 const unsigned char kV3Input[] = {
1163 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1
1164 0x00, 0x00, 0x00, 0x1a,
1165 0x00, 0x00, 0x00, 0x01,
1166 0x00, 0x00, 0x00, 0x00,
1167 0x00, 0x00, 0x00, 0x00,
1168 0x00, 0x01, 0x00, 0x00,
1169 0x00, 0x02, 'h', 'h',
1170 0x00, 0x00, 0x00, 0x02,
1171 'v', 'v',
1173 0x80, spdy_version_ch_, 0x00, 0x08, // HEADERS on Stream #1
1174 0x00, 0x00, 0x00, 0x20,
1175 0x00, 0x00, 0x00, 0x01,
1176 0x00, 0x00, 0x00, 0x02,
1177 0x00, 0x00, 0x00, 0x02,
1178 'h', '2',
1179 0x00, 0x00, 0x00, 0x02,
1180 'v', '2', 0x00, 0x00,
1181 0x00, 0x02, 'h', '3',
1182 0x00, 0x00, 0x00, 0x02,
1183 'v', '3',
1185 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1186 0x00, 0x00, 0x00, 0x0c,
1187 0xde, 0xad, 0xbe, 0xef,
1188 0xde, 0xad, 0xbe, 0xef,
1189 0xde, 0xad, 0xbe, 0xef,
1191 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #3
1192 0x00, 0x00, 0x00, 0x0e,
1193 0x00, 0x00, 0x00, 0x03,
1194 0x00, 0x00, 0x00, 0x00,
1195 0x00, 0x00, 0x00, 0x00,
1196 0x00, 0x00,
1198 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
1199 0x00, 0x00, 0x00, 0x08,
1200 0xde, 0xad, 0xbe, 0xef,
1201 0xde, 0xad, 0xbe, 0xef,
1203 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1204 0x00, 0x00, 0x00, 0x04,
1205 0xde, 0xad, 0xbe, 0xef,
1207 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #1
1208 0x00, 0x00, 0x00, 0x08,
1209 0x00, 0x00, 0x00, 0x01,
1210 0x00, 0x00, 0x00, 0x05, // RST_STREAM_CANCEL
1212 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
1213 0x00, 0x00, 0x00, 0x00,
1215 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #3
1216 0x00, 0x00, 0x00, 0x08,
1217 0x00, 0x00, 0x00, 0x03,
1218 0x00, 0x00, 0x00, 0x05, // RST_STREAM_CANCEL
1221 // SYN_STREAM doesn't exist in HTTP/2, so instead we send
1222 // HEADERS frames with PRIORITY and END_HEADERS set.
1223 const unsigned char kH2Input[] = {
1224 0x00, 0x00, 0x05, 0x01, // HEADERS: PRIORITY | END_HEADERS
1225 0x24, 0x00, 0x00, 0x00,
1226 0x01, 0x00, 0x00, 0x00, // Stream 1, Priority 0
1227 0x00, 0x82, // :method: GET
1229 0x00, 0x00, 0x01, 0x01, // HEADERS: END_HEADERS
1230 0x04, 0x00, 0x00, 0x00, // Stream 1
1231 0x01, 0x8c, // :status: 200
1233 0x00, 0x00, 0x0c, 0x00, // DATA on Stream #1
1234 0x00, 0x00, 0x00, 0x00,
1235 0x01, 0xde, 0xad, 0xbe,
1236 0xef, 0xde, 0xad, 0xbe,
1237 0xef, 0xde, 0xad, 0xbe,
1238 0xef,
1240 0x00, 0x00, 0x05, 0x01, // HEADERS: PRIORITY | END_HEADERS
1241 0x24, 0x00, 0x00, 0x00,
1242 0x03, 0x00, 0x00, 0x00, // Stream 3, Priority 0
1243 0x00, 0x82, // :method: GET
1245 0x00, 0x00, 0x08, 0x00, // DATA on Stream #3
1246 0x00, 0x00, 0x00, 0x00,
1247 0x03, 0xde, 0xad, 0xbe,
1248 0xef, 0xde, 0xad, 0xbe,
1249 0xef,
1251 0x00, 0x00, 0x04, 0x00, // DATA on Stream #1
1252 0x00, 0x00, 0x00, 0x00,
1253 0x01, 0xde, 0xad, 0xbe,
1254 0xef,
1256 0x00, 0x00, 0x04, 0x03, // RST_STREAM on Stream #1
1257 0x00, 0x00, 0x00, 0x00,
1258 0x01, 0x00, 0x00, 0x00,
1259 0x08, // RST_STREAM_CANCEL
1261 0x00, 0x00, 0x00, 0x00, // DATA on Stream #3
1262 0x00, 0x00, 0x00, 0x00,
1263 0x03,
1265 0x00, 0x00, 0x0f, 0x03, // RST_STREAM on Stream #3
1266 0x00, 0x00, 0x00, 0x00,
1267 0x03, 0x00, 0x00, 0x00, // RST_STREAM_CANCEL
1268 0x08, 0x52, 0x45, 0x53, // opaque data
1269 0x45, 0x54, 0x53, 0x54,
1270 0x52, 0x45, 0x41, 0x4d,
1273 TestSpdyVisitor visitor(spdy_version_);
1274 if (IsSpdy2()) {
1275 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
1276 } else if (IsSpdy3()) {
1277 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
1278 } else {
1279 visitor.SimulateInFramer(kH2Input, sizeof(kH2Input));
1282 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1283 EXPECT_EQ(24, visitor.data_bytes_);
1284 EXPECT_EQ(0, visitor.error_count_);
1285 EXPECT_EQ(2, visitor.fin_frame_count_);
1287 if (IsHttp2()) {
1288 EXPECT_EQ(3, visitor.headers_frame_count_);
1289 EXPECT_EQ(0, visitor.syn_frame_count_);
1290 base::StringPiece reset_stream = "RESETSTREAM";
1291 EXPECT_EQ(reset_stream, visitor.fin_opaque_data_);
1292 } else {
1293 EXPECT_EQ(1, visitor.headers_frame_count_);
1294 EXPECT_EQ(2, visitor.syn_frame_count_);
1295 EXPECT_TRUE(visitor.fin_opaque_data_.empty());
1298 EXPECT_EQ(0, visitor.fin_flag_count_);
1299 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
1300 EXPECT_EQ(4, visitor.data_frame_count_);
1301 visitor.fin_opaque_data_.clear();
1304 // Test that the FIN flag on a data frame signifies EOF.
1305 TEST_P(SpdyFramerTest, FinOnDataFrame) {
1306 const unsigned char kV2Input[] = {
1307 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1
1308 0x00, 0x00, 0x00, 0x14,
1309 0x00, 0x00, 0x00, 0x01,
1310 0x00, 0x00, 0x00, 0x00,
1311 0x00, 0x00, 0x00, 0x01,
1312 0x00, 0x02, 'h', 'h',
1313 0x00, 0x02, 'v', 'v',
1315 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1
1316 0x00, 0x00, 0x00, 0x10,
1317 0x00, 0x00, 0x00, 0x01,
1318 0x00, 0x00, 0x00, 0x01,
1319 0x00, 0x02, 'a', 'a',
1320 0x00, 0x02, 'b', 'b',
1322 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1323 0x00, 0x00, 0x00, 0x0c,
1324 0xde, 0xad, 0xbe, 0xef,
1325 0xde, 0xad, 0xbe, 0xef,
1326 0xde, 0xad, 0xbe, 0xef,
1328 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF
1329 0x01, 0x00, 0x00, 0x04,
1330 0xde, 0xad, 0xbe, 0xef,
1332 const unsigned char kV3Input[] = {
1333 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1
1334 0x00, 0x00, 0x00, 0x1a,
1335 0x00, 0x00, 0x00, 0x01,
1336 0x00, 0x00, 0x00, 0x00,
1337 0x00, 0x00, 0x00, 0x00,
1338 0x00, 0x01, 0x00, 0x00,
1339 0x00, 0x02, 'h', 'h',
1340 0x00, 0x00, 0x00, 0x02,
1341 'v', 'v',
1343 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1
1344 0x00, 0x00, 0x00, 0x14,
1345 0x00, 0x00, 0x00, 0x01,
1346 0x00, 0x00, 0x00, 0x01,
1347 0x00, 0x00, 0x00, 0x02,
1348 'a', 'a', 0x00, 0x00,
1349 0x00, 0x02, 'b', 'b',
1351 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
1352 0x00, 0x00, 0x00, 0x0c,
1353 0xde, 0xad, 0xbe, 0xef,
1354 0xde, 0xad, 0xbe, 0xef,
1355 0xde, 0xad, 0xbe, 0xef,
1357 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF
1358 0x01, 0x00, 0x00, 0x04,
1359 0xde, 0xad, 0xbe, 0xef,
1362 // SYN_STREAM and SYN_REPLY don't exist in HTTP/2, so instead we send
1363 // HEADERS frames with PRIORITY(SYN_STREAM only) and END_HEADERS set.
1364 const unsigned char kH2Input[] = {
1365 0x00, 0x00, 0x05, 0x01, // HEADERS: PRIORITY | END_HEADERS
1366 0x24, 0x00, 0x00, 0x00, // Stream 1
1367 0x01, 0x00, 0x00, 0x00, // Priority 0
1368 0x00, 0x82, // :method: GET
1370 0x00, 0x00, 0x01, 0x01, // HEADERS: END_HEADERS
1371 0x04, 0x00, 0x00, 0x00, // Stream 1
1372 0x01, 0x8c, // :status: 200
1374 0x00, 0x00, 0x0c, 0x00, // DATA on Stream #1
1375 0x00, 0x00, 0x00, 0x00,
1376 0x01, 0xde, 0xad, 0xbe,
1377 0xef, 0xde, 0xad, 0xbe,
1378 0xef, 0xde, 0xad, 0xbe,
1379 0xef,
1381 0x00, 0x00, 0x04, 0x00, // DATA on Stream #1, with FIN
1382 0x01, 0x00, 0x00, 0x00,
1383 0x01, 0xde, 0xad, 0xbe,
1384 0xef,
1387 TestSpdyVisitor visitor(spdy_version_);
1388 if (IsSpdy2()) {
1389 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
1390 } else if (IsSpdy3()) {
1391 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
1392 } else {
1393 visitor.SimulateInFramer(kH2Input, sizeof(kH2Input));
1396 EXPECT_EQ(0, visitor.error_count_);
1397 if (IsHttp2()) {
1398 EXPECT_EQ(0, visitor.syn_frame_count_);
1399 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1400 EXPECT_EQ(2, visitor.headers_frame_count_);
1401 } else {
1402 EXPECT_EQ(1, visitor.syn_frame_count_);
1403 EXPECT_EQ(1, visitor.syn_reply_frame_count_);
1404 EXPECT_EQ(0, visitor.headers_frame_count_);
1406 EXPECT_EQ(16, visitor.data_bytes_);
1407 EXPECT_EQ(0, visitor.fin_frame_count_);
1408 EXPECT_EQ(0, visitor.fin_flag_count_);
1409 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1410 EXPECT_EQ(2, visitor.data_frame_count_);
1413 // Test that the FIN flag on a SYN reply frame signifies EOF.
1414 TEST_P(SpdyFramerTest, FinOnSynReplyFrame) {
1415 const unsigned char kV2Input[] = {
1416 0x80, spdy_version_ch_, 0x00, // SYN Stream #1
1417 0x01, 0x00, 0x00, 0x00,
1418 0x14, 0x00, 0x00, 0x00,
1419 0x01, 0x00, 0x00, 0x00,
1420 0x00, 0x00, 0x00, 0x00,
1421 0x01, 0x00, 0x02, 'h',
1422 'h', 0x00, 0x02, 'v',
1423 'v',
1425 0x80, spdy_version_ch_, 0x00, // SYN REPLY Stream #1
1426 0x02, 0x01, 0x00, 0x00,
1427 0x10, 0x00, 0x00, 0x00,
1428 0x01, 0x00, 0x00, 0x00,
1429 0x01, 0x00, 0x02, 'a',
1430 'a', 0x00, 0x02, 'b',
1431 'b',
1433 const unsigned char kV3Input[] = {
1434 0x80, spdy_version_ch_, 0x00, // SYN Stream #1
1435 0x01, 0x00, 0x00, 0x00,
1436 0x1a, 0x00, 0x00, 0x00,
1437 0x01, 0x00, 0x00, 0x00,
1438 0x00, 0x00, 0x00, 0x00,
1439 0x00, 0x00, 0x01, 0x00,
1440 0x00, 0x00, 0x02, 'h',
1441 'h', 0x00, 0x00, 0x00,
1442 0x02, 'v', 'v',
1444 0x80, spdy_version_ch_, 0x00, // SYN REPLY Stream #1
1445 0x02, 0x01, 0x00, 0x00,
1446 0x14, 0x00, 0x00, 0x00,
1447 0x01, 0x00, 0x00, 0x00,
1448 0x01, 0x00, 0x00, 0x00,
1449 0x02, 'a', 'a', 0x00,
1450 0x00, 0x00, 0x02, 'b',
1451 'b',
1454 // SYN_STREAM and SYN_REPLY don't exist in HTTP/2, so instead we send
1455 // HEADERS frames with PRIORITY(SYN_STREAM only) and END_HEADERS set.
1456 const unsigned char kH2Input[] = {
1457 0x00, 0x00, 0x05, 0x01, // HEADERS: PRIORITY | END_HEADERS
1458 0x24, 0x00, 0x00, 0x00,
1459 0x01, 0x00, 0x00, 0x00, // Stream 1, Priority 0
1460 0x00, 0x82, // :method: GET
1462 0x00, 0x00, 0x01, 0x01, // HEADERS: FIN | END_HEADERS
1463 0x05, 0x00, 0x00, 0x00,
1464 0x01, 0x8c, // Stream 1, :status: 200
1467 TestSpdyVisitor visitor(spdy_version_);
1468 if (IsSpdy2()) {
1469 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
1470 } else if (IsSpdy3()) {
1471 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
1472 } else {
1473 visitor.SimulateInFramer(kH2Input, sizeof(kH2Input));
1476 EXPECT_EQ(0, visitor.error_count_);
1477 if (IsHttp2()) {
1478 EXPECT_EQ(0, visitor.syn_frame_count_);
1479 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1480 EXPECT_EQ(2, visitor.headers_frame_count_);
1481 } else {
1482 EXPECT_EQ(1, visitor.syn_frame_count_);
1483 EXPECT_EQ(1, visitor.syn_reply_frame_count_);
1484 EXPECT_EQ(0, visitor.headers_frame_count_);
1486 EXPECT_EQ(0, visitor.data_bytes_);
1487 EXPECT_EQ(0, visitor.fin_frame_count_);
1488 EXPECT_EQ(1, visitor.fin_flag_count_);
1489 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1490 EXPECT_EQ(0, visitor.data_frame_count_);
1493 TEST_P(SpdyFramerTest, HeaderCompression) {
1494 if (spdy_version_ > SPDY3) {
1495 // Deflate compression doesn't apply to HPACK.
1496 return;
1498 SpdyFramer send_framer(spdy_version_);
1499 SpdyFramer recv_framer(spdy_version_);
1501 send_framer.set_enable_compression(true);
1502 recv_framer.set_enable_compression(true);
1504 const char kHeader1[] = "header1";
1505 const char kHeader2[] = "header2";
1506 const char kHeader3[] = "header3";
1507 const char kValue1[] = "value1";
1508 const char kValue2[] = "value2";
1509 const char kValue3[] = "value3";
1511 // SYN_STREAM #1
1512 SpdyHeaderBlock block;
1513 block[kHeader1] = kValue1;
1514 block[kHeader2] = kValue2;
1515 SpdySynStreamIR syn_ir_1(1);
1516 syn_ir_1.set_header_block(block);
1517 scoped_ptr<SpdyFrame> syn_frame_1(send_framer.SerializeFrame(syn_ir_1));
1518 EXPECT_TRUE(syn_frame_1.get() != NULL);
1520 // SYN_STREAM #2
1521 block[kHeader3] = kValue3;
1522 SpdySynStreamIR syn_stream(3);
1523 syn_stream.set_header_block(block);
1524 scoped_ptr<SpdyFrame> syn_frame_2(send_framer.SerializeSynStream(syn_stream));
1525 EXPECT_TRUE(syn_frame_2.get() != NULL);
1527 // Now start decompressing
1528 scoped_ptr<SpdyFrame> decompressed;
1529 scoped_ptr<SpdyFrame> uncompressed;
1530 base::StringPiece serialized_headers;
1531 SpdyHeaderBlock decompressed_headers;
1533 // Decompress SYN_STREAM #1
1534 decompressed.reset(
1535 SpdyFramerTestUtil::DecompressFrame(&recv_framer, *syn_frame_1));
1536 EXPECT_TRUE(decompressed.get() != NULL);
1537 serialized_headers = GetSerializedHeaders(decompressed.get(), send_framer);
1538 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
1539 serialized_headers.size(),
1540 &decompressed_headers));
1541 EXPECT_EQ(2u, decompressed_headers.size());
1542 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
1543 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
1545 // Decompress SYN_STREAM #2
1546 decompressed.reset(
1547 SpdyFramerTestUtil::DecompressFrame(&recv_framer, *syn_frame_2));
1548 EXPECT_TRUE(decompressed.get() != NULL);
1549 serialized_headers = GetSerializedHeaders(decompressed.get(), send_framer);
1550 decompressed_headers.clear();
1551 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
1552 serialized_headers.size(),
1553 &decompressed_headers));
1554 EXPECT_EQ(3u, decompressed_headers.size());
1555 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
1556 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
1557 EXPECT_EQ(kValue3, decompressed_headers[kHeader3]);
1560 // Verify we can decompress the stream even if handed over to the
1561 // framer 1 byte at a time.
1562 TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) {
1563 SpdyFramer send_framer(spdy_version_);
1565 send_framer.set_enable_compression(true);
1567 const char kHeader1[] = "header1";
1568 const char kHeader2[] = "header2";
1569 const char kValue1[] = "value1";
1570 const char kValue2[] = "value2";
1572 SpdyHeadersIR headers(1);
1573 headers.SetHeader(kHeader1, kValue1);
1574 headers.SetHeader(kHeader2, kValue2);
1575 scoped_ptr<SpdyFrame> headers_frame(send_framer.SerializeHeaders(headers));
1576 EXPECT_TRUE(headers_frame.get() != NULL);
1578 const char bytes[] = "this is a test test test test test!";
1579 SpdyDataIR data_ir(1, StringPiece(bytes, arraysize(bytes)));
1580 data_ir.set_fin(true);
1581 scoped_ptr<SpdyFrame> send_frame(send_framer.SerializeData(data_ir));
1582 EXPECT_TRUE(send_frame.get() != NULL);
1584 // Run the inputs through the framer.
1585 TestSpdyVisitor visitor(spdy_version_);
1586 visitor.use_compression_ = true;
1587 const unsigned char* data;
1588 data = reinterpret_cast<const unsigned char*>(headers_frame->data());
1589 for (size_t idx = 0; idx < headers_frame->size(); ++idx) {
1590 visitor.SimulateInFramer(data + idx, 1);
1591 ASSERT_EQ(0, visitor.error_count_);
1593 data = reinterpret_cast<const unsigned char*>(send_frame->data());
1594 for (size_t idx = 0; idx < send_frame->size(); ++idx) {
1595 visitor.SimulateInFramer(data + idx, 1);
1596 ASSERT_EQ(0, visitor.error_count_);
1599 EXPECT_EQ(0, visitor.error_count_);
1600 EXPECT_EQ(0, visitor.syn_frame_count_);
1601 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1602 EXPECT_EQ(1, visitor.headers_frame_count_);
1603 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_));
1604 EXPECT_EQ(0, visitor.fin_frame_count_);
1605 EXPECT_EQ(0, visitor.fin_flag_count_);
1606 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1607 EXPECT_EQ(1, visitor.data_frame_count_);
1610 TEST_P(SpdyFramerTest, WindowUpdateFrame) {
1611 SpdyFramer framer(spdy_version_);
1612 scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate(
1613 SpdyWindowUpdateIR(1, 0x12345678)));
1615 const char kDescription[] = "WINDOW_UPDATE frame, stream 1, delta 0x12345678";
1616 const unsigned char kV3FrameData[] = { // Also applies for V2.
1617 0x80, spdy_version_ch_, 0x00, 0x09,
1618 0x00, 0x00, 0x00, 0x08,
1619 0x00, 0x00, 0x00, 0x01,
1620 0x12, 0x34, 0x56, 0x78
1622 const unsigned char kH2FrameData[] = {
1623 0x00, 0x00, 0x04, 0x08,
1624 0x00, 0x00, 0x00, 0x00,
1625 0x01, 0x12, 0x34, 0x56,
1626 0x78
1629 if (IsHttp2()) {
1630 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
1631 } else {
1632 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1636 TEST_P(SpdyFramerTest, CreateDataFrame) {
1637 SpdyFramer framer(spdy_version_);
1640 const char kDescription[] = "'hello' data frame, no FIN";
1641 const unsigned char kV3FrameData[] = { // Also applies for V2.
1642 0x00, 0x00, 0x00, 0x01,
1643 0x00, 0x00, 0x00, 0x05,
1644 'h', 'e', 'l', 'l',
1647 const unsigned char kH2FrameData[] = {0x00,
1648 0x00,
1649 0x05,
1650 0x00,
1651 0x00,
1652 0x00,
1653 0x00,
1654 0x00,
1655 0x01,
1656 'h',
1657 'e',
1658 'l',
1659 'l',
1660 'o'};
1661 const char bytes[] = "hello";
1663 SpdyDataIR data_ir(1, bytes);
1664 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
1665 if (IsHttp2()) {
1666 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
1667 } else {
1668 CompareFrame(
1669 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1672 SpdyDataIR data_header_ir(1);
1673 data_header_ir.SetDataShallow(bytes);
1674 frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField(
1675 data_header_ir));
1676 CompareCharArraysWithHexError(
1677 kDescription, reinterpret_cast<const unsigned char*>(frame->data()),
1678 framer.GetDataFrameMinimumSize(),
1679 IsHttp2() ? kH2FrameData : kV3FrameData,
1680 framer.GetDataFrameMinimumSize());
1684 const char kDescription[] = "'hello' data frame with more padding, no FIN";
1685 const unsigned char kV3FrameData[] = { // Also applies for V2.
1686 0x00, 0x00, 0x00, 0x01,
1687 0x00, 0x00, 0x00, 0x05,
1688 'h', 'e', 'l', 'l',
1692 const unsigned char kH2FrameData[] = {
1693 0x00, 0x00, 0xfd, 0x00, // Length = 253. PADDED set.
1694 0x08, 0x00, 0x00, 0x00,
1695 0x01, 0xf7, // Pad length field.
1696 'h', 'e', 'l', 'l', // Data
1697 'o',
1698 // Padding of 247 0x00(s).
1699 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1700 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1701 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1702 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1703 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1704 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1705 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1706 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1707 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1708 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1709 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1710 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1711 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1712 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1713 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1714 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1715 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1716 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1717 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1718 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1719 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1721 const char bytes[] = "hello";
1723 SpdyDataIR data_ir(1, bytes);
1724 // 247 zeros and the pad length field make the overall padding to be 248
1725 // bytes.
1726 data_ir.set_padding_len(248);
1727 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
1728 if (IsHttp2()) {
1729 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
1730 } else {
1731 CompareFrame(
1732 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1735 frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir));
1736 CompareCharArraysWithHexError(
1737 kDescription, reinterpret_cast<const unsigned char*>(frame->data()),
1738 framer.GetDataFrameMinimumSize(),
1739 IsHttp2() ? kH2FrameData : kV3FrameData,
1740 framer.GetDataFrameMinimumSize());
1744 const char kDescription[] = "'hello' data frame with few padding, no FIN";
1745 const unsigned char kV3FrameData[] = { // Also applies for V2.
1746 0x00, 0x00, 0x00, 0x01,
1747 0x00, 0x00, 0x00, 0x05,
1748 'h', 'e', 'l', 'l',
1752 const unsigned char kH2FrameData[] = {
1753 0x00, 0x00, 0x0d, 0x00, // Length = 13. PADDED set.
1754 0x08, 0x00, 0x00, 0x00,
1755 0x01, 0x07, // Pad length field.
1756 'h', 'e', 'l', 'l', // Data
1757 'o',
1758 0x00, 0x00, 0x00, 0x00, // Padding
1759 0x00, 0x00, 0x00
1761 const char bytes[] = "hello";
1763 SpdyDataIR data_ir(1, bytes);
1764 // 7 zeros and the pad length field make the overall padding to be 8 bytes.
1765 data_ir.set_padding_len(8);
1766 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
1767 if (IsHttp2()) {
1768 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
1769 } else {
1770 CompareFrame(
1771 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1776 const char kDescription[] =
1777 "'hello' data frame with 1 byte padding, no FIN";
1778 const unsigned char kV3FrameData[] = { // Also applies for V2.
1779 0x00, 0x00, 0x00, 0x01,
1780 0x00, 0x00, 0x00, 0x05,
1781 'h', 'e', 'l', 'l',
1785 const unsigned char kH2FrameData[] = {
1786 0x00, 0x00, 0x06, 0x00, // Length = 6. PADDED set.
1787 0x08, 0x00, 0x00, 0x00,
1788 0x01, 0x00, // Pad length field.
1789 'h', 'e', 'l', 'l', // Data
1790 'o',
1792 const char bytes[] = "hello";
1794 SpdyDataIR data_ir(1, bytes);
1795 // The pad length field itself is used for the 1-byte padding and no padding
1796 // payload is needed.
1797 data_ir.set_padding_len(1);
1798 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
1799 if (IsHttp2()) {
1800 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
1801 } else {
1802 CompareFrame(
1803 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1806 frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir));
1807 CompareCharArraysWithHexError(
1808 kDescription, reinterpret_cast<const unsigned char*>(frame->data()),
1809 framer.GetDataFrameMinimumSize(),
1810 IsHttp2() ? kH2FrameData : kV3FrameData,
1811 framer.GetDataFrameMinimumSize());
1815 const char kDescription[] = "Data frame with negative data byte, no FIN";
1816 const unsigned char kV3FrameData[] = { // Also applies for V2.
1817 0x00, 0x00, 0x00, 0x01,
1818 0x00, 0x00, 0x00, 0x01,
1819 0xff
1821 const unsigned char kH2FrameData[] = {
1822 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff};
1823 SpdyDataIR data_ir(1, "\xff");
1824 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
1825 if (IsHttp2()) {
1826 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
1827 } else {
1828 CompareFrame(
1829 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1834 const char kDescription[] = "'hello' data frame, with FIN";
1835 const unsigned char kV3FrameData[] = { // Also applies for V2.
1836 0x00, 0x00, 0x00, 0x01,
1837 0x01, 0x00, 0x00, 0x05,
1838 'h', 'e', 'l', 'l',
1841 const unsigned char kH2FrameData[] = {
1842 0x00, 0x00, 0x05, 0x00,
1843 0x01, 0x00, 0x00, 0x00,
1844 0x01, 'h', 'e', 'l',
1845 'l', 'o'
1847 SpdyDataIR data_ir(1, "hello");
1848 data_ir.set_fin(true);
1849 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
1850 if (IsHttp2()) {
1851 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
1852 } else {
1853 CompareFrame(
1854 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1859 const char kDescription[] = "Empty data frame";
1860 const unsigned char kV3FrameData[] = { // Also applies for V2.
1861 0x00, 0x00, 0x00, 0x01,
1862 0x00, 0x00, 0x00, 0x00,
1864 const unsigned char kH2FrameData[] = {
1865 0x00, 0x00, 0x00, 0x00,
1866 0x00, 0x00, 0x00, 0x00,
1867 0x01,
1869 SpdyDataIR data_ir(1, "");
1870 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
1871 if (IsHttp2()) {
1872 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
1873 } else {
1874 CompareFrame(
1875 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1878 frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir));
1879 CompareCharArraysWithHexError(
1880 kDescription, reinterpret_cast<const unsigned char*>(frame->data()),
1881 framer.GetDataFrameMinimumSize(),
1882 IsHttp2() ? kH2FrameData : kV3FrameData,
1883 framer.GetDataFrameMinimumSize());
1887 const char kDescription[] = "Data frame with max stream ID";
1888 const unsigned char kV3FrameData[] = { // Also applies for V2.
1889 0x7f, 0xff, 0xff, 0xff,
1890 0x01, 0x00, 0x00, 0x05,
1891 'h', 'e', 'l', 'l',
1894 const unsigned char kH2FrameData[] = {
1895 0x00, 0x00, 0x05, 0x00,
1896 0x01, 0x7f, 0xff, 0xff,
1897 0xff, 'h', 'e', 'l',
1898 'l', 'o'
1900 SpdyDataIR data_ir(0x7fffffff, "hello");
1901 data_ir.set_fin(true);
1902 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
1903 if (IsHttp2()) {
1904 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
1905 } else {
1906 CompareFrame(
1907 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1911 if (!IsHttp2()) {
1912 // This test does not apply to HTTP/2 because the max frame size is smaller
1913 // than 4MB.
1914 const char kDescription[] = "Large data frame";
1915 const int kDataSize = 4 * 1024 * 1024; // 4 MB
1916 const string kData(kDataSize, 'A');
1917 const unsigned char kFrameHeader[] = {
1918 0x00, 0x00, 0x00, 0x01,
1919 0x01, 0x40, 0x00, 0x00,
1922 const int kFrameSize = arraysize(kFrameHeader) + kDataSize;
1923 scoped_ptr<unsigned char[]> expected_frame_data(
1924 new unsigned char[kFrameSize]);
1925 memcpy(expected_frame_data.get(), kFrameHeader, arraysize(kFrameHeader));
1926 memset(expected_frame_data.get() + arraysize(kFrameHeader), 'A', kDataSize);
1928 SpdyDataIR data_ir(1, kData);
1929 data_ir.set_fin(true);
1930 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
1931 CompareFrame(kDescription, *frame, expected_frame_data.get(), kFrameSize);
1935 TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
1936 if (!IsSpdy2() && !IsSpdy3()) {
1937 // SYN_STREAM unsupported in SPDY>3
1938 return;
1940 SpdyFramer framer(spdy_version_);
1941 framer.set_enable_compression(false);
1944 const char kDescription[] = "SYN_STREAM frame, lowest pri, no FIN";
1946 const unsigned char kPri = IsSpdy2() ? 0xC0 : 0xE0;
1947 const unsigned char kV2FrameData[] = {
1948 0x80, spdy_version_ch_, 0x00, 0x01,
1949 0x00, 0x00, 0x00, 0x20,
1950 0x00, 0x00, 0x00, 0x01,
1951 0x00, 0x00, 0x00, 0x00,
1952 kPri, 0x00, 0x00, 0x02,
1953 0x00, 0x03, 'b', 'a',
1954 'r', 0x00, 0x03, 'f',
1955 'o', 'o', 0x00, 0x03,
1956 'f', 'o', 'o', 0x00,
1957 0x03, 'b', 'a', 'r'
1959 const unsigned char kV3FrameData[] = {
1960 0x80, spdy_version_ch_, 0x00, 0x01,
1961 0x00, 0x00, 0x00, 0x2a,
1962 0x00, 0x00, 0x00, 0x01,
1963 0x00, 0x00, 0x00, 0x00,
1964 kPri, 0x00, 0x00, 0x00,
1965 0x00, 0x02, 0x00, 0x00,
1966 0x00, 0x03, 'b', 'a',
1967 'r', 0x00, 0x00, 0x00,
1968 0x03, 'f', 'o', 'o',
1969 0x00, 0x00, 0x00, 0x03,
1970 'f', 'o', 'o', 0x00,
1971 0x00, 0x00, 0x03, 'b',
1972 'a', 'r'
1974 SpdySynStreamIR syn_stream(1);
1975 syn_stream.set_priority(framer.GetLowestPriority());
1976 syn_stream.SetHeader("bar", "foo");
1977 syn_stream.SetHeader("foo", "bar");
1978 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream));
1979 if (IsSpdy2()) {
1980 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
1981 } else if (IsSpdy3()) {
1982 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1983 } else {
1984 LOG(FATAL) << "Unsupported version in test.";
1989 const char kDescription[] =
1990 "SYN_STREAM frame with a 0-length header name, highest pri, FIN, "
1991 "max stream ID";
1993 const unsigned char kV2FrameData[] = {
1994 0x80, spdy_version_ch_, 0x00, 0x01,
1995 0x01, 0x00, 0x00, 0x1D,
1996 0x7f, 0xff, 0xff, 0xff,
1997 0x7f, 0xff, 0xff, 0xff,
1998 0x00, 0x00, 0x00, 0x02,
1999 0x00, 0x00, 0x00, 0x03,
2000 'f', 'o', 'o', 0x00,
2001 0x03, 'f', 'o', 'o',
2002 0x00, 0x03, 'b', 'a',
2005 const unsigned char kV3FrameData[] = {
2006 0x80, spdy_version_ch_, 0x00, 0x01,
2007 0x01, 0x00, 0x00, 0x27,
2008 0x7f, 0xff, 0xff, 0xff,
2009 0x7f, 0xff, 0xff, 0xff,
2010 0x00, 0x00, 0x00, 0x00,
2011 0x00, 0x02, 0x00, 0x00,
2012 0x00, 0x00, 0x00, 0x00,
2013 0x00, 0x03, 'f', 'o',
2014 'o', 0x00, 0x00, 0x00,
2015 0x03, 'f', 'o', 'o',
2016 0x00, 0x00, 0x00, 0x03,
2017 'b', 'a', 'r'
2019 SpdySynStreamIR syn_stream(0x7fffffff);
2020 syn_stream.set_associated_to_stream_id(0x7fffffff);
2021 syn_stream.set_priority(framer.GetHighestPriority());
2022 syn_stream.set_fin(true);
2023 syn_stream.SetHeader("", "foo");
2024 syn_stream.SetHeader("foo", "bar");
2025 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream));
2026 if (IsSpdy2()) {
2027 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2028 } else if (IsSpdy3()) {
2029 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2030 } else {
2031 LOG(FATAL) << "Unsupported version in test.";
2036 const char kDescription[] =
2037 "SYN_STREAM frame with a 0-length header val, high pri, FIN, "
2038 "max stream ID";
2040 const unsigned char kPri = IsSpdy2() ? 0x40 : 0x20;
2041 const unsigned char kV2FrameData[] = {
2042 0x80, spdy_version_ch_, 0x00, 0x01,
2043 0x01, 0x00, 0x00, 0x1D,
2044 0x7f, 0xff, 0xff, 0xff,
2045 0x7f, 0xff, 0xff, 0xff,
2046 kPri, 0x00, 0x00, 0x02,
2047 0x00, 0x03, 'b', 'a',
2048 'r', 0x00, 0x03, 'f',
2049 'o', 'o', 0x00, 0x03,
2050 'f', 'o', 'o', 0x00,
2051 0x00
2053 const unsigned char kV3FrameData[] = {
2054 0x80, spdy_version_ch_, 0x00, 0x01,
2055 0x01, 0x00, 0x00, 0x27,
2056 0x7f, 0xff, 0xff, 0xff,
2057 0x7f, 0xff, 0xff, 0xff,
2058 kPri, 0x00, 0x00, 0x00,
2059 0x00, 0x02, 0x00, 0x00,
2060 0x00, 0x03, 'b', 'a',
2061 'r', 0x00, 0x00, 0x00,
2062 0x03, 'f', 'o', 'o',
2063 0x00, 0x00, 0x00, 0x03,
2064 'f', 'o', 'o', 0x00,
2065 0x00, 0x00, 0x00
2067 SpdySynStreamIR syn_stream(0x7fffffff);
2068 syn_stream.set_associated_to_stream_id(0x7fffffff);
2069 syn_stream.set_priority(1);
2070 syn_stream.set_fin(true);
2071 syn_stream.SetHeader("bar", "foo");
2072 syn_stream.SetHeader("foo", "");
2073 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream));
2074 if (IsSpdy2()) {
2075 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2076 } else if (IsSpdy3()) {
2077 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2078 } else {
2079 LOG(FATAL) << "Unsupported version in test.";
2084 // TODO(phajdan.jr): Clean up after we no longer need
2085 // to workaround http://crbug.com/139744.
2086 #if !defined(USE_SYSTEM_ZLIB)
2087 TEST_P(SpdyFramerTest, CreateSynStreamCompressed) {
2088 if (!IsSpdy2() && !IsSpdy3()) {
2089 // SYN_STREAM not supported for SPDY>3
2090 return;
2092 SpdyFramer framer(spdy_version_);
2093 framer.set_enable_compression(true);
2096 const char kDescription[] =
2097 "SYN_STREAM frame, low pri, no FIN";
2098 const SpdyPriority priority = IsSpdy2() ? 2 : 4;
2100 const unsigned char kV2FrameData[] = {
2101 0x80, spdy_version_ch_, 0x00, 0x01,
2102 0x00, 0x00, 0x00, 0x36,
2103 0x00, 0x00, 0x00, 0x01,
2104 0x00, 0x00, 0x00, 0x00,
2105 0x80, 0x00, 0x38, 0xea,
2106 0xdf, 0xa2, 0x51, 0xb2,
2107 0x62, 0x60, 0x62, 0x60,
2108 0x4e, 0x4a, 0x2c, 0x62,
2109 0x60, 0x06, 0x08, 0xa0,
2110 0xb4, 0xfc, 0x7c, 0x80,
2111 0x00, 0x62, 0x60, 0x4e,
2112 0xcb, 0xcf, 0x67, 0x60,
2113 0x06, 0x08, 0xa0, 0xa4,
2114 0xc4, 0x22, 0x80, 0x00,
2115 0x02, 0x00, 0x00, 0x00,
2116 0xff, 0xff,
2118 const unsigned char kV3FrameData[] = {
2119 0x80, spdy_version_ch_, 0x00, 0x01,
2120 0x00, 0x00, 0x00, 0x37,
2121 0x00, 0x00, 0x00, 0x01,
2122 0x00, 0x00, 0x00, 0x00,
2123 0x80, 0x00, 0x38, 0xEA,
2124 0xE3, 0xC6, 0xA7, 0xC2,
2125 0x02, 0xE5, 0x0E, 0x50,
2126 0xC2, 0x4B, 0x4A, 0x04,
2127 0xE5, 0x0B, 0x66, 0x80,
2128 0x00, 0x4A, 0xCB, 0xCF,
2129 0x07, 0x08, 0x20, 0x10,
2130 0x95, 0x96, 0x9F, 0x0F,
2131 0xA2, 0x00, 0x02, 0x28,
2132 0x29, 0xB1, 0x08, 0x20,
2133 0x80, 0x00, 0x00, 0x00,
2134 0x00, 0xFF, 0xFF,
2136 const unsigned char kV2SIMDFrameData[] = {
2137 0x80, spdy_version_ch_, 0x00, 0x01,
2138 0x00, 0x00, 0x00, 0x33,
2139 0x00, 0x00, 0x00, 0x01,
2140 0x00, 0x00, 0x00, 0x00,
2141 0x80, 0x00, 0x38, 0xea,
2142 0xdf, 0xa2, 0x51, 0xb2,
2143 0x62, 0x60, 0x62, 0x60,
2144 0x4e, 0x4a, 0x2c, 0x62,
2145 0x60, 0x06, 0x08, 0xa0,
2146 0xb4, 0xfc, 0x7c, 0x80,
2147 0x00, 0x62, 0x60, 0x06,
2148 0x13, 0x00, 0x01, 0x94,
2149 0x94, 0x58, 0x04, 0x10,
2150 0x40, 0x00, 0x00, 0x00,
2151 0x00, 0xff, 0xff,
2153 const unsigned char kV3SIMDFrameData[] = {
2154 0x80, spdy_version_ch_, 0x00, 0x01,
2155 0x00, 0x00, 0x00, 0x32,
2156 0x00, 0x00, 0x00, 0x01,
2157 0x00, 0x00, 0x00, 0x00,
2158 0x80, 0x00, 0x38, 0xea,
2159 0xe3, 0xc6, 0xa7, 0xc2,
2160 0x02, 0xe5, 0x0e, 0x50,
2161 0xc2, 0x4b, 0x4a, 0x04,
2162 0xe5, 0x0b, 0x66, 0x80,
2163 0x00, 0x4a, 0xcb, 0xcf,
2164 0x07, 0x08, 0x20, 0x24,
2165 0x0a, 0x20, 0x80, 0x92,
2166 0x12, 0x8b, 0x00, 0x02,
2167 0x08, 0x00, 0x00, 0x00,
2168 0xff, 0xff,
2171 SpdySynStreamIR syn_stream(1);
2172 syn_stream.set_priority(priority);
2173 syn_stream.SetHeader("bar", "foo");
2174 syn_stream.SetHeader("foo", "bar");
2175 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream));
2176 const unsigned char* frame_data =
2177 reinterpret_cast<const unsigned char*>(frame->data());
2178 if (IsSpdy2()) {
2179 // Try comparing with SIMD version, if that fails, do a failing check
2180 // with pretty printing against non-SIMD version
2181 if (memcmp(frame_data,
2182 kV2SIMDFrameData,
2183 std::min(arraysize(kV2SIMDFrameData), frame->size())) != 0) {
2184 CompareCharArraysWithHexError(kDescription,
2185 frame_data,
2186 frame->size(),
2187 kV2FrameData,
2188 arraysize(kV2FrameData));
2190 } else if (IsSpdy3()) {
2191 if (memcmp(frame_data,
2192 kV3SIMDFrameData,
2193 std::min(arraysize(kV3SIMDFrameData), frame->size())) != 0) {
2194 CompareCharArraysWithHexError(kDescription,
2195 frame_data,
2196 frame->size(),
2197 kV3FrameData,
2198 arraysize(kV3FrameData));
2200 } else {
2201 LOG(FATAL) << "Unsupported version in test.";
2205 #endif // !defined(USE_SYSTEM_ZLIB)
2207 TEST_P(SpdyFramerTest, CreateSynReplyUncompressed) {
2208 if (spdy_version_ > SPDY3) {
2209 // SYN_REPLY unsupported in SPDY>3
2210 return;
2212 SpdyFramer framer(spdy_version_);
2213 framer.set_enable_compression(false);
2216 const char kDescription[] = "SYN_REPLY frame, no FIN";
2218 const unsigned char kV2FrameData[] = {
2219 0x80, spdy_version_ch_, 0x00, 0x02,
2220 0x00, 0x00, 0x00, 0x1C,
2221 0x00, 0x00, 0x00, 0x01,
2222 0x00, 0x00, 0x00, 0x02,
2223 0x00, 0x03, 'b', 'a',
2224 'r', 0x00, 0x03, 'f',
2225 'o', 'o', 0x00, 0x03,
2226 'f', 'o', 'o', 0x00,
2227 0x03, 'b', 'a', 'r'
2229 const unsigned char kV3FrameData[] = {
2230 0x80, spdy_version_ch_, 0x00, 0x02,
2231 0x00, 0x00, 0x00, 0x24,
2232 0x00, 0x00, 0x00, 0x01,
2233 0x00, 0x00, 0x00, 0x02,
2234 0x00, 0x00, 0x00, 0x03,
2235 'b', 'a', 'r', 0x00,
2236 0x00, 0x00, 0x03, 'f',
2237 'o', 'o', 0x00, 0x00,
2238 0x00, 0x03, 'f', 'o',
2239 'o', 0x00, 0x00, 0x00,
2240 0x03, 'b', 'a', 'r'
2242 SpdySynReplyIR syn_reply(1);
2243 syn_reply.SetHeader("bar", "foo");
2244 syn_reply.SetHeader("foo", "bar");
2245 scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply));
2246 if (IsSpdy2()) {
2247 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2248 } else if (IsSpdy3()) {
2249 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2250 } else {
2251 LOG(FATAL) << "Unsupported version in test.";
2256 const char kDescription[] =
2257 "SYN_REPLY frame with a 0-length header name, FIN, max stream ID";
2259 const unsigned char kV2FrameData[] = {
2260 0x80, spdy_version_ch_, 0x00, 0x02,
2261 0x01, 0x00, 0x00, 0x19,
2262 0x7f, 0xff, 0xff, 0xff,
2263 0x00, 0x00, 0x00, 0x02,
2264 0x00, 0x00, 0x00, 0x03,
2265 'f', 'o', 'o', 0x00,
2266 0x03, 'f', 'o', 'o',
2267 0x00, 0x03, 'b', 'a',
2270 const unsigned char kV3FrameData[] = {
2271 0x80, spdy_version_ch_, 0x00, 0x02,
2272 0x01, 0x00, 0x00, 0x21,
2273 0x7f, 0xff, 0xff, 0xff,
2274 0x00, 0x00, 0x00, 0x02,
2275 0x00, 0x00, 0x00, 0x00,
2276 0x00, 0x00, 0x00, 0x03,
2277 'f', 'o', 'o', 0x00,
2278 0x00, 0x00, 0x03, 'f',
2279 'o', 'o', 0x00, 0x00,
2280 0x00, 0x03, 'b', 'a',
2283 SpdySynReplyIR syn_reply(0x7fffffff);
2284 syn_reply.set_fin(true);
2285 syn_reply.SetHeader("", "foo");
2286 syn_reply.SetHeader("foo", "bar");
2287 scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply));
2288 if (IsSpdy2()) {
2289 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2290 } else if (IsSpdy3()) {
2291 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2292 } else {
2293 LOG(FATAL) << "Unsupported version in test.";
2298 const char kDescription[] =
2299 "SYN_REPLY frame with a 0-length header val, FIN, max stream ID";
2301 const unsigned char kV2FrameData[] = {
2302 0x80, spdy_version_ch_, 0x00, 0x02,
2303 0x01, 0x00, 0x00, 0x19,
2304 0x7f, 0xff, 0xff, 0xff,
2305 0x00, 0x00, 0x00, 0x02,
2306 0x00, 0x03, 'b', 'a',
2307 'r', 0x00, 0x03, 'f',
2308 'o', 'o', 0x00, 0x03,
2309 'f', 'o', 'o', 0x00,
2310 0x00
2312 const unsigned char kV3FrameData[] = {
2313 0x80, spdy_version_ch_, 0x00, 0x02,
2314 0x01, 0x00, 0x00, 0x21,
2315 0x7f, 0xff, 0xff, 0xff,
2316 0x00, 0x00, 0x00, 0x02,
2317 0x00, 0x00, 0x00, 0x03,
2318 'b', 'a', 'r', 0x00,
2319 0x00, 0x00, 0x03, 'f',
2320 'o', 'o', 0x00, 0x00,
2321 0x00, 0x03, 'f', 'o',
2322 'o', 0x00, 0x00, 0x00,
2323 0x00
2325 SpdySynReplyIR syn_reply(0x7fffffff);
2326 syn_reply.set_fin(true);
2327 syn_reply.SetHeader("bar", "foo");
2328 syn_reply.SetHeader("foo", "");
2329 scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply));
2330 if (IsSpdy2()) {
2331 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2332 } else if (IsSpdy3()) {
2333 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2334 } else {
2335 LOG(FATAL) << "Unsupported version in test.";
2340 // TODO(phajdan.jr): Clean up after we no longer need
2341 // to workaround http://crbug.com/139744.
2342 #if !defined(USE_SYSTEM_ZLIB)
2343 TEST_P(SpdyFramerTest, CreateSynReplyCompressed) {
2344 if (spdy_version_ > SPDY3) {
2345 // SYN_REPLY unsupported in SPDY>3
2346 return;
2348 SpdyFramer framer(spdy_version_);
2349 framer.set_enable_compression(true);
2352 const char kDescription[] = "SYN_REPLY frame, no FIN";
2354 const unsigned char kV2FrameData[] = {
2355 0x80, spdy_version_ch_, 0x00, 0x02,
2356 0x00, 0x00, 0x00, 0x32,
2357 0x00, 0x00, 0x00, 0x01,
2358 0x00, 0x00, 0x38, 0xea,
2359 0xdf, 0xa2, 0x51, 0xb2,
2360 0x62, 0x60, 0x62, 0x60,
2361 0x4e, 0x4a, 0x2c, 0x62,
2362 0x60, 0x06, 0x08, 0xa0,
2363 0xb4, 0xfc, 0x7c, 0x80,
2364 0x00, 0x62, 0x60, 0x4e,
2365 0xcb, 0xcf, 0x67, 0x60,
2366 0x06, 0x08, 0xa0, 0xa4,
2367 0xc4, 0x22, 0x80, 0x00,
2368 0x02, 0x00, 0x00, 0x00,
2369 0xff, 0xff,
2371 const unsigned char kV3FrameData[] = {
2372 0x80, spdy_version_ch_, 0x00, 0x02,
2373 0x00, 0x00, 0x00, 0x31,
2374 0x00, 0x00, 0x00, 0x01,
2375 0x38, 0xea, 0xe3, 0xc6,
2376 0xa7, 0xc2, 0x02, 0xe5,
2377 0x0e, 0x50, 0xc2, 0x4b,
2378 0x4a, 0x04, 0xe5, 0x0b,
2379 0x66, 0x80, 0x00, 0x4a,
2380 0xcb, 0xcf, 0x07, 0x08,
2381 0x20, 0x10, 0x95, 0x96,
2382 0x9f, 0x0f, 0xa2, 0x00,
2383 0x02, 0x28, 0x29, 0xb1,
2384 0x08, 0x20, 0x80, 0x00,
2385 0x00, 0x00, 0x00, 0xff,
2386 0xff,
2388 const unsigned char kV2SIMDFrameData[] = {
2389 0x80, spdy_version_ch_, 0x00, 0x02,
2390 0x00, 0x00, 0x00, 0x2f,
2391 0x00, 0x00, 0x00, 0x01,
2392 0x00, 0x00, 0x38, 0xea,
2393 0xdf, 0xa2, 0x51, 0xb2,
2394 0x62, 0x60, 0x62, 0x60,
2395 0x4e, 0x4a, 0x2c, 0x62,
2396 0x60, 0x06, 0x08, 0xa0,
2397 0xb4, 0xfc, 0x7c, 0x80,
2398 0x00, 0x62, 0x60, 0x06,
2399 0x13, 0x00, 0x01, 0x94,
2400 0x94, 0x58, 0x04, 0x10,
2401 0x40, 0x00, 0x00, 0x00,
2402 0x00, 0xff, 0xff,
2404 const unsigned char kV3SIMDFrameData[] = {
2405 0x80, spdy_version_ch_, 0x00, 0x02,
2406 0x00, 0x00, 0x00, 0x2c,
2407 0x00, 0x00, 0x00, 0x01,
2408 0x38, 0xea, 0xe3, 0xc6,
2409 0xa7, 0xc2, 0x02, 0xe5,
2410 0x0e, 0x50, 0xc2, 0x4b,
2411 0x4a, 0x04, 0xe5, 0x0b,
2412 0x66, 0x80, 0x00, 0x4a,
2413 0xcb, 0xcf, 0x07, 0x08,
2414 0x20, 0x24, 0x0a, 0x20,
2415 0x80, 0x92, 0x12, 0x8b,
2416 0x00, 0x02, 0x08, 0x00,
2417 0x00, 0x00, 0xff, 0xff,
2420 SpdySynReplyIR syn_reply(1);
2421 syn_reply.SetHeader("bar", "foo");
2422 syn_reply.SetHeader("foo", "bar");
2423 scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply));
2424 const unsigned char* frame_data =
2425 reinterpret_cast<const unsigned char*>(frame->data());
2426 if (IsSpdy2()) {
2427 // Try comparing with SIMD version, if that fails, do a failing check
2428 // with pretty printing against non-SIMD version
2429 if (memcmp(frame_data,
2430 kV2SIMDFrameData,
2431 std::min(arraysize(kV2SIMDFrameData), frame->size())) != 0) {
2432 CompareCharArraysWithHexError(kDescription,
2433 frame_data,
2434 frame->size(),
2435 kV2FrameData,
2436 arraysize(kV2FrameData));
2438 } else if (IsSpdy3()) {
2439 if (memcmp(frame_data,
2440 kV3SIMDFrameData,
2441 std::min(arraysize(kV3SIMDFrameData), frame->size())) != 0) {
2442 CompareCharArraysWithHexError(kDescription,
2443 frame_data,
2444 frame->size(),
2445 kV3FrameData,
2446 arraysize(kV3FrameData));
2448 } else {
2449 LOG(FATAL) << "Unsupported version in test.";
2453 #endif // !defined(USE_SYSTEM_ZLIB)
2455 TEST_P(SpdyFramerTest, CreateRstStream) {
2456 SpdyFramer framer(spdy_version_);
2459 const char kDescription[] = "RST_STREAM frame";
2460 const unsigned char kV3FrameData[] = { // Also applies for V2.
2461 0x80, spdy_version_ch_, 0x00, 0x03,
2462 0x00, 0x00, 0x00, 0x08,
2463 0x00, 0x00, 0x00, 0x01,
2464 0x00, 0x00, 0x00, 0x01,
2466 const unsigned char kH2FrameData[] = {
2467 0x00, 0x00, 0x07, 0x03,
2468 0x00, 0x00, 0x00, 0x00,
2469 0x01, 0x00, 0x00, 0x00,
2470 0x01, 0x52, 0x53, 0x54
2472 SpdyRstStreamIR rst_stream(1, RST_STREAM_PROTOCOL_ERROR, "RST");
2473 scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream));
2474 if (IsHttp2()) {
2475 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2476 } else {
2477 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2482 const char kDescription[] = "RST_STREAM frame with max stream ID";
2483 const unsigned char kV3FrameData[] = { // Also applies for V2.
2484 0x80, spdy_version_ch_, 0x00, 0x03,
2485 0x00, 0x00, 0x00, 0x08,
2486 0x7f, 0xff, 0xff, 0xff,
2487 0x00, 0x00, 0x00, 0x01,
2489 const unsigned char kH2FrameData[] = {
2490 0x00, 0x00, 0x04, 0x03,
2491 0x00, 0x7f, 0xff, 0xff,
2492 0xff, 0x00, 0x00, 0x00,
2493 0x01,
2495 SpdyRstStreamIR rst_stream(0x7FFFFFFF,
2496 RST_STREAM_PROTOCOL_ERROR,
2497 "");
2498 scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream));
2499 if (IsHttp2()) {
2500 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2501 } else {
2502 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2507 const char kDescription[] = "RST_STREAM frame with max status code";
2508 const unsigned char kV3FrameData[] = { // Also applies for V2.
2509 0x80, spdy_version_ch_, 0x00, 0x03,
2510 0x00, 0x00, 0x00, 0x08,
2511 0x7f, 0xff, 0xff, 0xff,
2512 0x00, 0x00, 0x00, 0x06,
2514 const unsigned char kH2FrameData[] = {
2515 0x00, 0x00, 0x04, 0x03,
2516 0x00, 0x7f, 0xff, 0xff,
2517 0xff, 0x00, 0x00, 0x00,
2518 0x02,
2520 SpdyRstStreamIR rst_stream(0x7FFFFFFF,
2521 RST_STREAM_INTERNAL_ERROR,
2522 "");
2523 scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream));
2524 if (IsHttp2()) {
2525 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2526 } else {
2527 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2532 TEST_P(SpdyFramerTest, CreateSettings) {
2533 SpdyFramer framer(spdy_version_);
2536 const char kDescription[] = "Network byte order SETTINGS frame";
2538 const unsigned char kV2FrameData[] = {
2539 0x80, spdy_version_ch_, 0x00, 0x04,
2540 0x00, 0x00, 0x00, 0x0c,
2541 0x00, 0x00, 0x00, 0x01,
2542 0x07, 0x00, 0x00, 0x01,
2543 0x0a, 0x0b, 0x0c, 0x0d,
2545 const unsigned char kV3FrameData[] = {
2546 0x80, spdy_version_ch_, 0x00, 0x04,
2547 0x00, 0x00, 0x00, 0x0c,
2548 0x00, 0x00, 0x00, 0x01,
2549 0x01, 0x00, 0x00, 0x07,
2550 0x0a, 0x0b, 0x0c, 0x0d,
2552 const unsigned char kH2FrameData[] = {
2553 0x00, 0x00, 0x06, 0x04,
2554 0x00, 0x00, 0x00, 0x00,
2555 0x00, 0x00, 0x04, 0x0a,
2556 0x0b, 0x0c, 0x0d,
2559 uint32 kValue = 0x0a0b0c0d;
2560 SpdySettingsIR settings_ir;
2562 SpdySettingsFlags kFlags = static_cast<SpdySettingsFlags>(0x01);
2563 SpdySettingsIds kId = SETTINGS_INITIAL_WINDOW_SIZE;
2564 settings_ir.AddSetting(kId,
2565 kFlags & SETTINGS_FLAG_PLEASE_PERSIST,
2566 kFlags & SETTINGS_FLAG_PERSISTED,
2567 kValue);
2569 scoped_ptr<SpdyFrame> frame(framer.SerializeSettings(settings_ir));
2570 if (IsSpdy2()) {
2571 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2572 } else if (IsSpdy3()) {
2573 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2574 } else {
2575 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2580 const char kDescription[] = "Basic SETTINGS frame";
2582 const unsigned char kV2FrameData[] = {
2583 0x80, spdy_version_ch_, 0x00, 0x04,
2584 0x00, 0x00, 0x00, 0x24,
2585 0x00, 0x00, 0x00, 0x04,
2586 0x01, 0x00, 0x00, 0x00, // 1st Setting
2587 0x00, 0x00, 0x00, 0x05,
2588 0x02, 0x00, 0x00, 0x00, // 2nd Setting
2589 0x00, 0x00, 0x00, 0x06,
2590 0x03, 0x00, 0x00, 0x00, // 3rd Setting
2591 0x00, 0x00, 0x00, 0x07,
2592 0x04, 0x00, 0x00, 0x00, // 4th Setting
2593 0x00, 0x00, 0x00, 0x08,
2595 const unsigned char kV3FrameData[] = {
2596 0x80, spdy_version_ch_, 0x00, 0x04,
2597 0x00, 0x00, 0x00, 0x24,
2598 0x00, 0x00, 0x00, 0x04,
2599 0x00, 0x00, 0x00, 0x01, // 1st Setting
2600 0x00, 0x00, 0x00, 0x05,
2601 0x00, 0x00, 0x00, 0x02, // 2nd Setting
2602 0x00, 0x00, 0x00, 0x06,
2603 0x00, 0x00, 0x00, 0x03, // 3rd Setting
2604 0x00, 0x00, 0x00, 0x07,
2605 0x00, 0x00, 0x00, 0x04, // 4th Setting
2606 0x00, 0x00, 0x00, 0x08,
2608 // These end up seemingly out of order because of the way that our internal
2609 // ordering for settings_ir works. HTTP2 has no requirement on ordering on
2610 // the wire.
2611 const unsigned char kH2FrameData[] = {
2612 0x00, 0x00, 0x18, 0x04,
2613 0x00, 0x00, 0x00, 0x00,
2614 0x00, 0x00, 0x03, // 3rd Setting
2615 0x00, 0x00, 0x00, 0x07,
2616 0x00, 0x04, // 4th Setting
2617 0x00, 0x00, 0x00, 0x08,
2618 0x00, 0x01, // 1st Setting
2619 0x00, 0x00, 0x00, 0x05,
2620 0x00, 0x02, // 2nd Setting
2621 0x00, 0x00, 0x00, 0x06,
2624 SpdySettingsIR settings_ir;
2625 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 1),
2626 false, // persist
2627 false, // persisted
2629 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 2),
2630 false, // persist
2631 false, // persisted
2633 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 3),
2634 false, // persist
2635 false, // persisted
2637 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 4),
2638 false, // persist
2639 false, // persisted
2641 scoped_ptr<SpdyFrame> frame(framer.SerializeSettings(settings_ir));
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, kH2FrameData, arraysize(kH2FrameData));
2653 const char kDescription[] = "Empty SETTINGS frame";
2655 const unsigned char kV3FrameData[] = { // Also applies for V2.
2656 0x80, spdy_version_ch_, 0x00, 0x04,
2657 0x00, 0x00, 0x00, 0x04,
2658 0x00, 0x00, 0x00, 0x00,
2660 const unsigned char kH2FrameData[] = {
2661 0x00, 0x00, 0x00, 0x04,
2662 0x00, 0x00, 0x00, 0x00,
2663 0x00,
2665 SpdySettingsIR settings_ir;
2666 scoped_ptr<SpdyFrame> frame(framer.SerializeSettings(settings_ir));
2667 if (IsHttp2()) {
2668 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2669 } else {
2670 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2675 TEST_P(SpdyFramerTest, CreatePingFrame) {
2676 SpdyFramer framer(spdy_version_);
2679 const char kDescription[] = "PING frame";
2680 const unsigned char kV3FrameData[] = { // Also applies for V2.
2681 0x80, spdy_version_ch_, 0x00, 0x06,
2682 0x00, 0x00, 0x00, 0x04,
2683 0x12, 0x34, 0x56, 0x78,
2685 const unsigned char kH2FrameData[] = {
2686 0x00, 0x00, 0x08, 0x06,
2687 0x00, 0x00, 0x00, 0x00,
2688 0x00, 0x12, 0x34, 0x56,
2689 0x78, 0x9a, 0xbc, 0xde,
2690 0xff,
2692 const unsigned char kH2FrameDataWithAck[] = {
2693 0x00, 0x00, 0x08, 0x06,
2694 0x01, 0x00, 0x00, 0x00,
2695 0x00, 0x12, 0x34, 0x56,
2696 0x78, 0x9a, 0xbc, 0xde,
2697 0xff,
2699 scoped_ptr<SpdyFrame> frame;
2700 if (IsHttp2()) {
2701 const SpdyPingId kPingId = 0x123456789abcdeffULL;
2702 SpdyPingIR ping_ir(kPingId);
2703 // Tests SpdyPingIR when the ping is not an ack.
2704 ASSERT_FALSE(ping_ir.is_ack());
2705 frame.reset(framer.SerializePing(ping_ir));
2706 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2708 // Tests SpdyPingIR when the ping is an ack.
2709 ping_ir.set_is_ack(true);
2710 frame.reset(framer.SerializePing(ping_ir));
2711 CompareFrame(kDescription, *frame, kH2FrameDataWithAck,
2712 arraysize(kH2FrameDataWithAck));
2714 } else {
2715 frame.reset(framer.SerializePing(SpdyPingIR(0x12345678ull)));
2716 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2721 TEST_P(SpdyFramerTest, CreateGoAway) {
2722 SpdyFramer framer(spdy_version_);
2725 const char kDescription[] = "GOAWAY frame";
2726 const unsigned char kV2FrameData[] = {
2727 0x80, spdy_version_ch_, 0x00, 0x07,
2728 0x00, 0x00, 0x00, 0x04,
2729 0x00, 0x00, 0x00, 0x00, // Stream Id
2731 const unsigned char kV3FrameData[] = {
2732 0x80, spdy_version_ch_, 0x00, 0x07,
2733 0x00, 0x00, 0x00, 0x08,
2734 0x00, 0x00, 0x00, 0x00, // Stream Id
2735 0x00, 0x00, 0x00, 0x00, // Status
2737 const unsigned char kH2FrameData[] = {
2738 0x00, 0x00, 0x0a, 0x07,
2739 0x00, 0x00, 0x00, 0x00,
2740 0x00, 0x00, 0x00, 0x00, // Stream id
2741 0x00, 0x00, 0x00, 0x00, // Status
2742 0x00, 0x47, 0x41, // Opaque Description
2744 SpdyGoAwayIR goaway_ir(0, GOAWAY_OK, "GA");
2745 scoped_ptr<SpdyFrame> frame(framer.SerializeGoAway(goaway_ir));
2746 if (IsSpdy2()) {
2747 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2748 } else if (IsSpdy3()) {
2749 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2750 } else {
2751 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2756 const char kDescription[] = "GOAWAY frame with max stream ID, status";
2757 const unsigned char kV2FrameData[] = {
2758 0x80, spdy_version_ch_, 0x00, 0x07,
2759 0x00, 0x00, 0x00, 0x04,
2760 0x7f, 0xff, 0xff, 0xff, // Stream Id
2762 const unsigned char kV3FrameData[] = {
2763 0x80, spdy_version_ch_, 0x00, 0x07,
2764 0x00, 0x00, 0x00, 0x08,
2765 0x7f, 0xff, 0xff, 0xff, // Stream Id
2766 0x00, 0x00, 0x00, 0x01, // Status: PROTOCOL_ERROR.
2768 const unsigned char kH2FrameData[] = {
2769 0x00, 0x00, 0x0a, 0x07,
2770 0x00, 0x00, 0x00, 0x00,
2771 0x00, 0x7f, 0xff, 0xff, // Stream Id
2772 0xff, 0x00, 0x00, 0x00, // Status: INTERNAL_ERROR.
2773 0x02, 0x47, 0x41, // Opaque Description
2775 SpdyGoAwayIR goaway_ir(0x7FFFFFFF, GOAWAY_INTERNAL_ERROR, "GA");
2776 scoped_ptr<SpdyFrame> frame(framer.SerializeGoAway(goaway_ir));
2777 if (IsSpdy2()) {
2778 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2779 } else if (IsSpdy3()) {
2780 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2781 } else {
2782 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2787 TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
2788 SpdyFramer framer(spdy_version_);
2789 framer.set_enable_compression(false);
2792 const char kDescription[] = "HEADERS frame, no FIN";
2794 const unsigned char kV2FrameData[] = {
2795 0x80, spdy_version_ch_, 0x00, 0x08,
2796 0x00, 0x00, 0x00, 0x1C,
2797 0x00, 0x00, 0x00, 0x01,
2798 0x00, 0x00, 0x00, 0x02,
2799 0x00, 0x03, 'b', 'a',
2800 'r', 0x00, 0x03, 'f',
2801 'o', 'o', 0x00, 0x03,
2802 'f', 'o', 'o', 0x00,
2803 0x03, 'b', 'a', 'r'
2805 const unsigned char kV3FrameData[] = {
2806 0x80, spdy_version_ch_, 0x00, 0x08,
2807 0x00, 0x00, 0x00, 0x24,
2808 0x00, 0x00, 0x00, 0x01,
2809 0x00, 0x00, 0x00, 0x02,
2810 0x00, 0x00, 0x00, 0x03,
2811 'b', 'a', 'r', 0x00,
2812 0x00, 0x00, 0x03, 'f',
2813 'o', 'o', 0x00, 0x00,
2814 0x00, 0x03, 'f', 'o',
2815 'o', 0x00, 0x00, 0x00,
2816 0x03, 'b', 'a', 'r'
2818 const unsigned char kH2FrameData[] = {
2819 0x00, 0x00, 0x12, 0x01, // Headers: END_HEADERS
2820 0x04, 0x00, 0x00, 0x00, // Stream 1
2821 0x01, 0x00, 0x03, 0x62, // @.ba
2822 0x61, 0x72, 0x03, 0x66, // r.fo
2823 0x6f, 0x6f, 0x00, 0x03, // o@.f
2824 0x66, 0x6f, 0x6f, 0x03, // oo.b
2825 0x62, 0x61, 0x72, // ar
2827 SpdyHeadersIR headers_ir(1);
2828 headers_ir.SetHeader("bar", "foo");
2829 headers_ir.SetHeader("foo", "bar");
2830 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
2831 if (IsSpdy2()) {
2832 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2833 } else if (IsSpdy3()) {
2834 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2835 } else {
2836 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2841 const char kDescription[] =
2842 "HEADERS frame with a 0-length header name, FIN, max stream ID";
2844 const unsigned char kV2FrameData[] = {
2845 0x80, spdy_version_ch_, 0x00, 0x08,
2846 0x01, 0x00, 0x00, 0x19,
2847 0x7f, 0xff, 0xff, 0xff,
2848 0x00, 0x00, 0x00, 0x02,
2849 0x00, 0x00, 0x00, 0x03,
2850 'f', 'o', 'o', 0x00,
2851 0x03, 'f', 'o', 'o',
2852 0x00, 0x03, 'b', 'a',
2855 const unsigned char kV3FrameData[] = {
2856 0x80, spdy_version_ch_, 0x00, 0x08,
2857 0x01, 0x00, 0x00, 0x21,
2858 0x7f, 0xff, 0xff, 0xff,
2859 0x00, 0x00, 0x00, 0x02,
2860 0x00, 0x00, 0x00, 0x00,
2861 0x00, 0x00, 0x00, 0x03,
2862 'f', 'o', 'o', 0x00,
2863 0x00, 0x00, 0x03, 'f',
2864 'o', 'o', 0x00, 0x00,
2865 0x00, 0x03, 'b', 'a',
2868 const unsigned char kH2FrameData[] = {
2869 0x00, 0x00, 0x0f, 0x01, // Headers: FIN | END_HEADERS
2870 0x05, 0x7f, 0xff, 0xff, // Stream 0x7fffffff
2871 0xff, 0x00, 0x00, 0x03, // @..
2872 0x66, 0x6f, 0x6f, 0x00, // foo@
2873 0x03, 0x66, 0x6f, 0x6f, // .foo
2874 0x03, 0x62, 0x61, 0x72, // .bar
2876 SpdyHeadersIR headers_ir(0x7fffffff);
2877 headers_ir.set_fin(true);
2878 headers_ir.SetHeader("", "foo");
2879 headers_ir.SetHeader("foo", "bar");
2880 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
2881 if (IsSpdy2()) {
2882 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2883 } else if (IsSpdy3()) {
2884 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2885 } else {
2886 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2891 const char kDescription[] =
2892 "HEADERS frame with a 0-length header val, FIN, max stream ID";
2894 const unsigned char kV2FrameData[] = {
2895 0x80, spdy_version_ch_, 0x00, 0x08,
2896 0x01, 0x00, 0x00, 0x19,
2897 0x7f, 0xff, 0xff, 0xff,
2898 0x00, 0x00, 0x00, 0x02,
2899 0x00, 0x03, 'b', 'a',
2900 'r', 0x00, 0x03, 'f',
2901 'o', 'o', 0x00, 0x03,
2902 'f', 'o', 'o', 0x00,
2903 0x00
2905 const unsigned char kV3FrameData[] = {
2906 0x80, spdy_version_ch_, 0x00, 0x08,
2907 0x01, 0x00, 0x00, 0x21,
2908 0x7f, 0xff, 0xff, 0xff,
2909 0x00, 0x00, 0x00, 0x02,
2910 0x00, 0x00, 0x00, 0x03,
2911 'b', 'a', 'r', 0x00,
2912 0x00, 0x00, 0x03, 'f',
2913 'o', 'o', 0x00, 0x00,
2914 0x00, 0x03, 'f', 'o',
2915 'o', 0x00, 0x00, 0x00,
2916 0x00
2918 const unsigned char kH2FrameData[] = {
2919 0x00, 0x00, 0x0f, 0x01, // Headers: FIN | END_HEADERS
2920 0x05, 0x7f, 0xff, 0xff, // Stream 0x7fffffff
2921 0xff, 0x00, 0x03, 0x62, // @.b
2922 0x61, 0x72, 0x03, 0x66, // ar.f
2923 0x6f, 0x6f, 0x00, 0x03, // oo@.
2924 0x66, 0x6f, 0x6f, 0x00, // foo.
2926 SpdyHeadersIR headers_ir(0x7fffffff);
2927 headers_ir.set_fin(true);
2928 headers_ir.SetHeader("bar", "foo");
2929 headers_ir.SetHeader("foo", "");
2930 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
2931 if (IsSpdy2()) {
2932 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2933 } else if (IsSpdy3()) {
2934 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2935 } else {
2936 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2941 const char kDescription[] =
2942 "HEADERS frame with a 0-length header val, FIN, max stream ID, pri";
2944 const unsigned char kH2FrameData[] = {
2945 0x00, 0x00, 0x14, 0x01, // Headers: FIN | END_HEADERS | PRIORITY
2946 0x25, 0x7f, 0xff, 0xff, // Stream 0x7fffffff
2947 0xff, 0x00, 0x00, 0x00, // exclusive, parent stream
2948 0x00, 0xdb, // weight
2949 0x00, 0x03, 0x62, 0x61, // @.ba
2950 0x72, 0x03, 0x66, 0x6f, // r.fo
2951 0x6f, 0x00, 0x03, 0x66, // o@.f
2952 0x6f, 0x6f, 0x00, // oo.
2954 SpdyHeadersIR headers_ir(0x7fffffff);
2955 headers_ir.set_fin(true);
2956 headers_ir.set_priority(1);
2957 headers_ir.set_has_priority(true);
2958 headers_ir.SetHeader("bar", "foo");
2959 headers_ir.SetHeader("foo", "");
2960 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
2961 if (IsSpdy2() || IsSpdy3()) {
2962 // HEADERS with priority not supported.
2963 } else {
2964 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
2969 const char kDescription[] =
2970 "HEADERS frame with a 0-length header val, FIN, max stream ID, pri, "
2971 "exclusive=true, parent_stream=0";
2973 const unsigned char kH2FrameData[] = {
2974 0x00, 0x00, 0x14, 0x01, // Headers: FIN | END_HEADERS | PRIORITY
2975 0x25, 0x7f, 0xff, 0xff, // Stream 0x7fffffff
2976 0xff, 0x80, 0x00, 0x00, // exclusive, parent stream
2977 0x00, 0xdb, // weight
2978 0x00, 0x03, 0x62, 0x61, // @.ba
2979 0x72, 0x03, 0x66, 0x6f, // r.fo
2980 0x6f, 0x00, 0x03, 0x66, // o@.f
2981 0x6f, 0x6f, 0x00, // oo.
2983 SpdyHeadersIR headers_ir(0x7fffffff);
2984 headers_ir.set_fin(true);
2985 headers_ir.set_priority(1);
2986 headers_ir.set_has_priority(true);
2987 headers_ir.set_exclusive(true);
2988 headers_ir.set_parent_stream_id(0);
2989 headers_ir.SetHeader("bar", "foo");
2990 headers_ir.SetHeader("foo", "");
2991 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
2992 if (IsSpdy2() || IsSpdy3()) {
2993 // HEADERS with priority not supported.
2994 } else {
2995 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
3000 const char kDescription[] =
3001 "HEADERS frame with a 0-length header val, FIN, max stream ID, pri, "
3002 "exclusive=false, parent_stream=max stream ID";
3004 const unsigned char kH2FrameData[] = {
3005 0x00, 0x00, 0x14, 0x01, // Headers: FIN | END_HEADERS | PRIORITY
3006 0x25, 0x7f, 0xff, 0xff, // Stream 0x7fffffff
3007 0xff, 0x7f, 0xff, 0xff, // exclusive, parent stream
3008 0xff, 0xdb, // weight
3009 0x00, 0x03, 0x62, 0x61, // @.ba
3010 0x72, 0x03, 0x66, 0x6f, // r.fo
3011 0x6f, 0x00, 0x03, 0x66, // o@.f
3012 0x6f, 0x6f, 0x00, // oo.
3014 SpdyHeadersIR headers_ir(0x7fffffff);
3015 headers_ir.set_fin(true);
3016 headers_ir.set_priority(1);
3017 headers_ir.set_has_priority(true);
3018 headers_ir.set_exclusive(false);
3019 headers_ir.set_parent_stream_id(0x7fffffff);
3020 headers_ir.SetHeader("bar", "foo");
3021 headers_ir.SetHeader("foo", "");
3022 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
3023 if (IsSpdy2() || IsSpdy3()) {
3024 // HEADERS with priority not supported.
3025 } else {
3026 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
3031 const char kDescription[] =
3032 "HEADERS frame with a 0-length header name, FIN, max stream ID, padded";
3034 const unsigned char kH2FrameData[] = {
3035 0x00, 0x00, 0x15, 0x01, // Headers
3036 0x0d, 0x7f, 0xff, 0xff, // FIN | END_HEADERS | PADDED, Stream
3037 // 0x7fffffff
3038 0xff, 0x05, 0x00, 0x00, // Pad length field
3039 0x03, 0x66, 0x6f, 0x6f, // .foo
3040 0x00, 0x03, 0x66, 0x6f, // @.fo
3041 0x6f, 0x03, 0x62, 0x61, // o.ba
3042 0x72, // r
3043 // Padding payload
3044 0x00, 0x00, 0x00, 0x00, 0x00,
3046 SpdyHeadersIR headers_ir(0x7fffffff);
3047 headers_ir.set_fin(true);
3048 headers_ir.SetHeader("", "foo");
3049 headers_ir.SetHeader("foo", "bar");
3050 headers_ir.set_padding_len(6);
3051 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
3052 if (IsSpdy2() || IsSpdy3()) {
3053 // Padding is not supported.
3054 } else {
3055 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
3060 // TODO(phajdan.jr): Clean up after we no longer need
3061 // to workaround http://crbug.com/139744.
3062 #if !defined(USE_SYSTEM_ZLIB)
3063 TEST_P(SpdyFramerTest, CreateHeadersCompressed) {
3064 SpdyFramer framer(spdy_version_);
3065 framer.set_enable_compression(true);
3068 const char kDescription[] = "HEADERS frame, no FIN";
3070 const unsigned char kV2FrameData[] = {
3071 0x80, spdy_version_ch_, 0x00, 0x08,
3072 0x00, 0x00, 0x00, 0x32,
3073 0x00, 0x00, 0x00, 0x01,
3074 0x00, 0x00, 0x38, 0xea,
3075 0xdf, 0xa2, 0x51, 0xb2,
3076 0x62, 0x60, 0x62, 0x60,
3077 0x4e, 0x4a, 0x2c, 0x62,
3078 0x60, 0x06, 0x08, 0xa0,
3079 0xb4, 0xfc, 0x7c, 0x80,
3080 0x00, 0x62, 0x60, 0x4e,
3081 0xcb, 0xcf, 0x67, 0x60,
3082 0x06, 0x08, 0xa0, 0xa4,
3083 0xc4, 0x22, 0x80, 0x00,
3084 0x02, 0x00, 0x00, 0x00,
3085 0xff, 0xff,
3087 const unsigned char kV3FrameData[] = {
3088 0x80, spdy_version_ch_, 0x00, 0x08,
3089 0x00, 0x00, 0x00, 0x31,
3090 0x00, 0x00, 0x00, 0x01,
3091 0x38, 0xea, 0xe3, 0xc6,
3092 0xa7, 0xc2, 0x02, 0xe5,
3093 0x0e, 0x50, 0xc2, 0x4b,
3094 0x4a, 0x04, 0xe5, 0x0b,
3095 0x66, 0x80, 0x00, 0x4a,
3096 0xcb, 0xcf, 0x07, 0x08,
3097 0x20, 0x10, 0x95, 0x96,
3098 0x9f, 0x0f, 0xa2, 0x00,
3099 0x02, 0x28, 0x29, 0xb1,
3100 0x08, 0x20, 0x80, 0x00,
3101 0x00, 0x00, 0x00, 0xff,
3102 0xff,
3104 const unsigned char kV2SIMDFrameData[] = {
3105 0x80, spdy_version_ch_, 0x00, 0x08,
3106 0x00, 0x00, 0x00, 0x2f,
3107 0x00, 0x00, 0x00, 0x01,
3108 0x00, 0x00, 0x38, 0xea,
3109 0xdf, 0xa2, 0x51, 0xb2,
3110 0x62, 0x60, 0x62, 0x60,
3111 0x4e, 0x4a, 0x2c, 0x62,
3112 0x60, 0x06, 0x08, 0xa0,
3113 0xb4, 0xfc, 0x7c, 0x80,
3114 0x00, 0x62, 0x60, 0x06,
3115 0x13, 0x00, 0x01, 0x94,
3116 0x94, 0x58, 0x04, 0x10,
3117 0x40, 0x00, 0x00, 0x00,
3118 0x00, 0xff, 0xff,
3120 const unsigned char kV3SIMDFrameData[] = {
3121 0x80, spdy_version_ch_, 0x00, 0x08,
3122 0x00, 0x00, 0x00, 0x2c,
3123 0x00, 0x00, 0x00, 0x01,
3124 0x38, 0xea, 0xe3, 0xc6,
3125 0xa7, 0xc2, 0x02, 0xe5,
3126 0x0e, 0x50, 0xc2, 0x4b,
3127 0x4a, 0x04, 0xe5, 0x0b,
3128 0x66, 0x80, 0x00, 0x4a,
3129 0xcb, 0xcf, 0x07, 0x08,
3130 0x20, 0x24, 0x0a, 0x20,
3131 0x80, 0x92, 0x12, 0x8b,
3132 0x00, 0x02, 0x08, 0x00,
3133 0x00, 0x00, 0xff, 0xff,
3136 SpdyHeadersIR headers_ir(1);
3137 headers_ir.SetHeader("bar", "foo");
3138 headers_ir.SetHeader("foo", "bar");
3139 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
3140 const unsigned char* frame_data =
3141 reinterpret_cast<const unsigned char*>(frame->data());
3142 if (IsSpdy2()) {
3143 // Try comparing with SIMD version, if that fails, do a failing check
3144 // with pretty printing against non-SIMD version
3145 if (memcmp(frame_data,
3146 kV2SIMDFrameData,
3147 std::min(arraysize(kV2SIMDFrameData), frame->size())) != 0) {
3148 CompareCharArraysWithHexError(kDescription,
3149 frame_data,
3150 frame->size(),
3151 kV2FrameData,
3152 arraysize(kV2FrameData));
3154 } else if (IsSpdy3()) {
3155 if (memcmp(frame_data,
3156 kV3SIMDFrameData,
3157 std::min(arraysize(kV3SIMDFrameData), frame->size())) != 0) {
3158 CompareCharArraysWithHexError(kDescription,
3159 frame_data,
3160 frame->size(),
3161 kV3FrameData,
3162 arraysize(kV3FrameData));
3164 } else {
3165 // Deflate compression doesn't apply to HPACK.
3169 #endif // !defined(USE_SYSTEM_ZLIB)
3171 TEST_P(SpdyFramerTest, CreateWindowUpdate) {
3172 SpdyFramer framer(spdy_version_);
3175 const char kDescription[] = "WINDOW_UPDATE frame";
3176 const unsigned char kV3FrameData[] = { // Also applies for V2.
3177 0x80, spdy_version_ch_, 0x00, 0x09,
3178 0x00, 0x00, 0x00, 0x08,
3179 0x00, 0x00, 0x00, 0x01,
3180 0x00, 0x00, 0x00, 0x01,
3182 const unsigned char kH2FrameData[] = {
3183 0x00, 0x00, 0x04, 0x08,
3184 0x00, 0x00, 0x00, 0x00,
3185 0x01, 0x00, 0x00, 0x00,
3186 0x01,
3188 scoped_ptr<SpdyFrame> frame(
3189 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 1)));
3190 if (IsHttp2()) {
3191 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
3192 } else {
3193 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
3198 const char kDescription[] = "WINDOW_UPDATE frame with max stream ID";
3199 const unsigned char kV3FrameData[] = { // Also applies for V2.
3200 0x80, spdy_version_ch_, 0x00, 0x09,
3201 0x00, 0x00, 0x00, 0x08,
3202 0x7f, 0xff, 0xff, 0xff,
3203 0x00, 0x00, 0x00, 0x01,
3205 const unsigned char kH2FrameData[] = {
3206 0x00, 0x00, 0x04, 0x08,
3207 0x00, 0x7f, 0xff, 0xff,
3208 0xff, 0x00, 0x00, 0x00,
3209 0x01,
3211 scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate(
3212 SpdyWindowUpdateIR(0x7FFFFFFF, 1)));
3213 if (IsHttp2()) {
3214 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
3215 } else {
3216 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
3221 const char kDescription[] = "WINDOW_UPDATE frame with max window delta";
3222 const unsigned char kV3FrameData[] = { // Also applies for V2.
3223 0x80, spdy_version_ch_, 0x00, 0x09,
3224 0x00, 0x00, 0x00, 0x08,
3225 0x00, 0x00, 0x00, 0x01,
3226 0x7f, 0xff, 0xff, 0xff,
3228 const unsigned char kH2FrameData[] = {
3229 0x00, 0x00, 0x04, 0x08,
3230 0x00, 0x00, 0x00, 0x00,
3231 0x01, 0x7f, 0xff, 0xff,
3232 0xff,
3234 scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate(
3235 SpdyWindowUpdateIR(1, 0x7FFFFFFF)));
3236 if (IsHttp2()) {
3237 CompareFrame(kDescription, *frame, kH2FrameData, arraysize(kH2FrameData));
3238 } else {
3239 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
3244 TEST_P(SpdyFramerTest, SerializeBlocked) {
3245 if (spdy_version_ <= SPDY3) {
3246 return;
3249 SpdyFramer framer(spdy_version_);
3251 const char kDescription[] = "BLOCKED frame";
3252 const unsigned char kType = static_cast<unsigned char>(
3253 SpdyConstants::SerializeFrameType(spdy_version_, BLOCKED));
3254 const unsigned char kFrameData[] = {
3255 0x00, 0x00, 0x00, kType, 0x00,
3256 0x00, 0x00, 0x00, 0x00,
3258 SpdyBlockedIR blocked_ir(0);
3259 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(blocked_ir));
3260 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
3263 TEST_P(SpdyFramerTest, CreateBlocked) {
3264 if (spdy_version_ <= SPDY3) {
3265 return;
3268 SpdyFramer framer(spdy_version_);
3270 const char kDescription[] = "BLOCKED frame";
3271 const SpdyStreamId kStreamId = 3;
3273 scoped_ptr<SpdySerializedFrame> frame_serialized(
3274 framer.SerializeBlocked(SpdyBlockedIR(kStreamId)));
3275 SpdyBlockedIR blocked_ir(kStreamId);
3276 scoped_ptr<SpdySerializedFrame> frame_created(
3277 framer.SerializeFrame(blocked_ir));
3279 CompareFrames(kDescription, *frame_serialized, *frame_created);
3282 TEST_P(SpdyFramerTest, CreatePushPromiseUncompressed) {
3283 if (spdy_version_ <= SPDY3) {
3284 return;
3288 // Test framing PUSH_PROMISE without padding.
3289 SpdyFramer framer(spdy_version_);
3290 framer.set_enable_compression(false);
3291 const char kDescription[] = "PUSH_PROMISE frame without padding";
3293 const unsigned char kFrameData[] = {
3294 0x00, 0x00, 0x16, 0x05, // PUSH_PROMISE
3295 0x04, 0x00, 0x00, 0x00, // END_HEADERS
3296 0x2a, 0x00, 0x00, 0x00, // Stream 42
3297 0x39, 0x00, 0x03, 0x62, // Promised stream 57, @.b
3298 0x61, 0x72, 0x03, 0x66, // ar.f
3299 0x6f, 0x6f, 0x00, 0x03, // oo@.
3300 0x66, 0x6f, 0x6f, 0x03, // foo.
3301 0x62, 0x61, 0x72, // bar
3304 SpdyPushPromiseIR push_promise(42, 57);
3305 push_promise.SetHeader("bar", "foo");
3306 push_promise.SetHeader("foo", "bar");
3307 scoped_ptr<SpdySerializedFrame> frame(
3308 framer.SerializePushPromise(push_promise));
3309 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
3313 // Test framing PUSH_PROMISE with one byte of padding.
3314 SpdyFramer framer(spdy_version_);
3315 framer.set_enable_compression(false);
3316 const char kDescription[] = "PUSH_PROMISE frame with one byte of padding";
3318 const unsigned char kFrameData[] = {
3319 0x00, 0x00, 0x17, 0x05, // PUSH_PROMISE
3320 0x0c, 0x00, 0x00, 0x00, // END_HEADERS | PADDED
3321 0x2a, 0x00, 0x00, 0x00, // Stream 42, Pad length field
3322 0x00, 0x39, 0x00, 0x03, // Promised stream 57
3323 0x62, 0x61, 0x72, 0x03, // bar.
3324 0x66, 0x6f, 0x6f, 0x00, // foo@
3325 0x03, 0x66, 0x6f, 0x6f, // .foo
3326 0x03, 0x62, 0x61, 0x72, // .bar
3329 SpdyPushPromiseIR push_promise(42, 57);
3330 push_promise.set_padding_len(1);
3331 push_promise.SetHeader("bar", "foo");
3332 push_promise.SetHeader("foo", "bar");
3333 scoped_ptr<SpdySerializedFrame> frame(
3334 framer.SerializePushPromise(push_promise));
3335 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
3339 // Test framing PUSH_PROMISE with 177 bytes of padding.
3340 SpdyFramer framer(spdy_version_);
3341 framer.set_enable_compression(false);
3342 const char kDescription[] = "PUSH_PROMISE frame with 177 bytes of padding";
3344 const unsigned char kFrameData[] = {
3345 0x00, 0x00, 0xc7, 0x05, // PUSH_PROMISE
3346 0x0c, 0x00, 0x00, 0x00, // END_HEADERS | PADDED
3347 0x2a, 0xb0, 0x00, 0x00, // Stream 42, Pad length field
3348 0x00, 0x39, 0x00, 0x03, // Promised stream 57
3349 0x62, 0x61, 0x72, 0x03, // bar.
3350 0x66, 0x6f, 0x6f, 0x00, // foo@
3351 0x03, 0x66, 0x6f, 0x6f, // .foo
3352 0x03, 0x62, 0x61, 0x72, // .bar
3353 // Padding of 176 0x00(s).
3354 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3355 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3358 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3359 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3360 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3362 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3363 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3366 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3367 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3368 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3371 SpdyPushPromiseIR push_promise(42, 57);
3372 push_promise.set_padding_len(177);
3373 push_promise.SetHeader("bar", "foo");
3374 push_promise.SetHeader("foo", "bar");
3375 scoped_ptr<SpdySerializedFrame> frame(
3376 framer.SerializePushPromise(push_promise));
3377 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
3381 TEST_P(SpdyFramerTest, GetNumberRequiredContinuationFrames) {
3382 if (spdy_version_ <= SPDY3) {
3383 return;
3386 SpdyFramer framer(spdy_version_);
3387 // Test case from https://crbug.com/464748.
3388 EXPECT_EQ(1u,
3389 SpdyFramerPeer::GetNumberRequiredContinuationFrames(&framer, 2039));
3390 EXPECT_EQ(2u,
3391 SpdyFramerPeer::GetNumberRequiredContinuationFrames(&framer, 2040));
3394 TEST_P(SpdyFramerTest, CreateContinuationUncompressed) {
3395 if (spdy_version_ <= SPDY3) {
3396 return;
3399 SpdyFramer framer(spdy_version_);
3400 framer.set_enable_compression(false);
3401 const char kDescription[] = "CONTINUATION frame";
3403 const unsigned char kFrameData[] = {
3404 0x00, 0x00, 0x12, 0x09, // CONTINUATION
3405 0x04, 0x00, 0x00, 0x00, // end_headers = true
3406 0x2a, 0x00, 0x03, 0x62, // Stream 42, @.b
3407 0x61, 0x72, 0x03, 0x66, // ar.f
3408 0x6f, 0x6f, 0x00, 0x03, // oo@.
3409 0x66, 0x6f, 0x6f, 0x03, // foo.
3410 0x62, 0x61, 0x72, // bar
3413 SpdyContinuationIR continuation(42);
3414 continuation.SetHeader("bar", "foo");
3415 continuation.SetHeader("foo", "bar");
3416 continuation.set_end_headers(true);
3417 scoped_ptr<SpdySerializedFrame> frame(
3418 framer.SerializeContinuation(continuation));
3419 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
3422 TEST_P(SpdyFramerTest, CreatePushPromiseThenContinuationUncompressed) {
3423 if (spdy_version_ <= SPDY3) {
3424 return;
3428 // Test framing in a case such that a PUSH_PROMISE frame, with one byte of
3429 // padding, cannot hold all the data payload, which is overflowed to the
3430 // consecutive CONTINUATION frame.
3431 SpdyFramer framer(spdy_version_);
3432 framer.set_enable_compression(false);
3433 const char kDescription[] =
3434 "PUSH_PROMISE and CONTINUATION frames with one byte of padding";
3436 const unsigned char kPartialPushPromiseFrameData[] = {
3437 0x00, 0x03, 0xf7, 0x05, // PUSH_PROMISE
3438 0x08, 0x00, 0x00, 0x00, // PADDED
3439 0x2a, 0x00, 0x00, 0x00, // Stream 42
3440 0x00, 0x39, 0x00, 0x03, // Promised stream 57
3441 0x78, 0x78, 0x78, 0x7f, // xxx.
3442 0x81, 0x07, 0x78, 0x78, // ..xx
3443 0x78, 0x78, 0x78, 0x78, // xxxx
3444 0x78, 0x78, 0x78, 0x78, // xxxx
3445 0x78, 0x78, 0x78, 0x78, // xxxx
3446 0x78, 0x78, 0x78, 0x78, // xxxx
3447 0x78, 0x78, 0x78, 0x78, // xxxx
3448 0x78, 0x78, 0x78, 0x78, // xxxx
3449 0x78, 0x78, 0x78, 0x78, // xxxx
3450 0x78, 0x78, 0x78, 0x78, // xxxx
3451 0x78, 0x78, 0x78, 0x78, // xxxx
3452 0x78, 0x78, 0x78, 0x78, // xxxx
3453 0x78, 0x78, 0x78, 0x78, // xxxx
3454 0x78, 0x78, 0x78, 0x78, // xxxx
3455 0x78, 0x78, 0x78, 0x78, // xxxx
3456 0x78, 0x78, 0x78, 0x78, // xxxx
3457 0x78, 0x78, 0x78, 0x78, // xxxx
3458 0x78, 0x78, 0x78, 0x78, // xxxx
3459 0x78, 0x78, 0x78, 0x78, // xxxx
3460 0x78, 0x78, 0x78, 0x78, // xxxx
3461 0x78, 0x78, 0x78, 0x78, // xxxx
3462 0x78, 0x78, 0x78, 0x78, // xxxx
3463 0x78, 0x78, // xx
3466 const unsigned char kContinuationFrameData[] = {
3467 0x00, 0x00, 0x16, 0x09, // CONTINUATION
3468 0x04, 0x00, 0x00, 0x00, // END_HEADERS
3469 0x2a, 0x78, 0x78, 0x78, // Stream 42, xxx
3470 0x78, 0x78, 0x78, 0x78, // xxxx
3471 0x78, 0x78, 0x78, 0x78, // xxxx
3472 0x78, 0x78, 0x78, 0x78, // xxxx
3473 0x78, 0x78, 0x78, 0x78, // xxxx
3474 0x78, 0x78,
3477 SpdyPushPromiseIR push_promise(42, 57);
3478 push_promise.set_padding_len(1);
3479 string big_value(TestSpdyVisitor::sent_control_frame_max_size(), 'x');
3480 push_promise.SetHeader("xxx", big_value);
3481 scoped_ptr<SpdySerializedFrame> frame(
3482 framer.SerializePushPromise(push_promise));
3484 // The entire frame should look like below:
3485 // Name Length in Byte
3486 // ------------------------------------------- Begin of PUSH_PROMISE frame
3487 // PUSH_PROMISE header 9
3488 // Pad length field 1
3489 // Promised stream 4
3490 // Length field of key 2
3491 // Content of key 3
3492 // Length field of value 3
3493 // Part of big_value 16361
3494 // ------------------------------------------- Begin of CONTINUATION frame
3495 // CONTINUATION header 9
3496 // Remaining of big_value 22
3497 // ------------------------------------------- End
3499 // Length of everything listed above except big_value.
3500 int len_non_data_payload = 31;
3501 EXPECT_EQ(
3502 TestSpdyVisitor::sent_control_frame_max_size() + len_non_data_payload,
3503 frame->size());
3505 // Partially compare the PUSH_PROMISE frame against the template.
3506 const unsigned char* frame_data =
3507 reinterpret_cast<const unsigned char*>(frame->data());
3508 CompareCharArraysWithHexError(kDescription,
3509 frame_data,
3510 arraysize(kPartialPushPromiseFrameData),
3511 kPartialPushPromiseFrameData,
3512 arraysize(kPartialPushPromiseFrameData));
3514 // Compare the CONTINUATION frame against the template.
3515 frame_data += TestSpdyVisitor::sent_control_frame_max_size();
3516 CompareCharArraysWithHexError(kDescription,
3517 frame_data,
3518 arraysize(kContinuationFrameData),
3519 kContinuationFrameData,
3520 arraysize(kContinuationFrameData));
3524 TEST_P(SpdyFramerTest, CreateAltSvc) {
3525 if (spdy_version_ <= SPDY3) {
3526 return;
3529 SpdyFramer framer(spdy_version_);
3531 const char kDescription[] = "ALTSVC frame";
3532 const char kType = static_cast<unsigned char>(
3533 SpdyConstants::SerializeFrameType(spdy_version_, ALTSVC));
3534 const unsigned char kFrameData[] = {
3535 0x00, 0x00, 0x49, kType, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 'o',
3536 'r', 'i', 'g', 'i', 'n', 'p', 'i', 'd', '1', '=', '"', 'h',
3537 'o', 's', 't', ':', '4', '4', '3', '"', ';', ' ', 'm', 'a',
3538 '=', '5', ',', 'p', '%', '2', '2', '%', '3', 'D', 'i', '%',
3539 '3', 'A', 'd', '=', '"', 'h', '_', '\\', '\\', 'o', '\\', '"',
3540 's', 't', ':', '1', '2', '3', '"', ';', ' ', 'm', 'a', '=',
3541 '4', '2', ';', ' ', 'p', '=', '0', '.', '2', '0',
3543 SpdyAltSvcIR altsvc_ir(3);
3544 altsvc_ir.set_origin("origin");
3545 altsvc_ir.add_altsvc(
3546 SpdyAltSvcWireFormat::AlternativeService("pid1", "host", 443, 5, 1.0));
3547 altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService(
3548 "p\"=i:d", "h_\\o\"st", 123, 42, 0.2));
3549 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir));
3550 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
3553 TEST_P(SpdyFramerTest, CreatePriority) {
3554 if (spdy_version_ <= SPDY3) {
3555 return;
3558 SpdyFramer framer(spdy_version_);
3560 const char kDescription[] = "PRIORITY frame";
3561 const unsigned char kType = static_cast<unsigned char>(
3562 SpdyConstants::SerializeFrameType(spdy_version_, PRIORITY));
3563 const unsigned char kFrameData[] = {
3564 0x00, 0x00, 0x05, kType, 0x00,
3565 0x00, 0x00, 0x00, 0x02, // Stream ID = 2
3566 0x80, 0x00, 0x00, 0x01, // Exclusive dependency, parent stream ID = 1
3567 0x10, // Weight = 16
3569 SpdyPriorityIR priority_ir(2, 1, 16, true);
3570 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(priority_ir));
3571 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
3572 SpdyPriorityIR priority2(2);
3573 priority2.set_parent_stream_id(1);
3574 priority2.set_weight(16);
3575 priority2.set_exclusive(true);
3576 frame.reset(framer.SerializeFrame(priority2));
3577 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
3580 TEST_P(SpdyFramerTest, ReadCompressedSynStreamHeaderBlock) {
3581 if (spdy_version_ > SPDY3) {
3582 // SYN_STREAM not supported in SPDY>3
3583 return;
3585 SpdyFramer framer(spdy_version_);
3586 SpdySynStreamIR syn_stream(1);
3587 syn_stream.set_priority(1);
3588 syn_stream.SetHeader("aa", "vv");
3589 syn_stream.SetHeader("bb", "ww");
3590 SpdyHeaderBlock headers = syn_stream.header_block();
3591 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSynStream(syn_stream));
3592 EXPECT_TRUE(control_frame.get() != NULL);
3593 TestSpdyVisitor visitor(spdy_version_);
3594 visitor.use_compression_ = true;
3595 visitor.SimulateInFramer(
3596 reinterpret_cast<unsigned char*>(control_frame->data()),
3597 control_frame->size());
3598 EXPECT_EQ(1, visitor.syn_frame_count_);
3599 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
3602 TEST_P(SpdyFramerTest, ReadCompressedSynReplyHeaderBlock) {
3603 if (spdy_version_ > SPDY3) {
3604 return;
3606 SpdyFramer framer(spdy_version_);
3607 SpdySynReplyIR syn_reply(1);
3608 syn_reply.SetHeader("alpha", "beta");
3609 syn_reply.SetHeader("gamma", "delta");
3610 SpdyHeaderBlock headers = syn_reply.header_block();
3611 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSynReply(syn_reply));
3612 EXPECT_TRUE(control_frame.get() != NULL);
3613 TestSpdyVisitor visitor(spdy_version_);
3614 visitor.use_compression_ = true;
3615 visitor.SimulateInFramer(
3616 reinterpret_cast<unsigned char*>(control_frame->data()),
3617 control_frame->size());
3618 if (IsHttp2()) {
3619 EXPECT_EQ(0, visitor.syn_reply_frame_count_);
3620 EXPECT_EQ(1, visitor.headers_frame_count_);
3621 } else {
3622 EXPECT_EQ(1, visitor.syn_reply_frame_count_);
3623 EXPECT_EQ(0, visitor.headers_frame_count_);
3625 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
3628 TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) {
3629 SpdyFramer framer(spdy_version_);
3630 SpdyHeadersIR headers_ir(1);
3631 headers_ir.SetHeader("alpha", "beta");
3632 headers_ir.SetHeader("gamma", "delta");
3633 SpdyHeaderBlock headers = headers_ir.header_block();
3634 scoped_ptr<SpdyFrame> control_frame(framer.SerializeHeaders(headers_ir));
3635 EXPECT_TRUE(control_frame.get() != NULL);
3636 TestSpdyVisitor visitor(spdy_version_);
3637 visitor.use_compression_ = true;
3638 visitor.SimulateInFramer(
3639 reinterpret_cast<unsigned char*>(control_frame->data()),
3640 control_frame->size());
3641 EXPECT_EQ(1, visitor.headers_frame_count_);
3642 // control_frame_header_data_count_ depends on the random sequence
3643 // produced by rand(), so adding, removing or running single tests
3644 // alters this value. The best we can do is assert that it happens
3645 // at least twice.
3646 EXPECT_LE(2, visitor.control_frame_header_data_count_);
3647 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
3648 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
3649 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
3652 TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) {
3653 SpdyFramer framer(spdy_version_);
3654 SpdyHeadersIR headers_ir(1);
3655 headers_ir.set_fin(true);
3656 headers_ir.SetHeader("alpha", "beta");
3657 headers_ir.SetHeader("gamma", "delta");
3658 SpdyHeaderBlock headers = headers_ir.header_block();
3659 scoped_ptr<SpdyFrame> control_frame(framer.SerializeHeaders(headers_ir));
3660 EXPECT_TRUE(control_frame.get() != NULL);
3661 TestSpdyVisitor visitor(spdy_version_);
3662 visitor.use_compression_ = true;
3663 visitor.SimulateInFramer(
3664 reinterpret_cast<unsigned char*>(control_frame->data()),
3665 control_frame->size());
3666 EXPECT_EQ(1, visitor.headers_frame_count_);
3667 // control_frame_header_data_count_ depends on the random sequence
3668 // produced by rand(), so adding, removing or running single tests
3669 // alters this value. The best we can do is assert that it happens
3670 // at least twice.
3671 EXPECT_LE(2, visitor.control_frame_header_data_count_);
3672 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
3673 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
3674 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
3677 TEST_P(SpdyFramerTest, ControlFrameAtMaxSizeLimit) {
3678 if (spdy_version_ > SPDY3) {
3679 // TODO(jgraettinger): This test setup doesn't work with HPACK.
3680 return;
3682 // First find the size of the header value in order to just reach the control
3683 // frame max size.
3684 SpdyFramer framer(spdy_version_);
3685 framer.set_enable_compression(false);
3686 SpdySynStreamIR syn_stream(1);
3687 syn_stream.set_priority(1);
3688 syn_stream.SetHeader("aa", "");
3689 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSynStream(syn_stream));
3690 const size_t kBigValueSize =
3691 TestSpdyVisitor::sent_control_frame_max_size() - control_frame->size();
3693 // Create a frame at exactly that size.
3694 string big_value(kBigValueSize, 'x');
3695 syn_stream.SetHeader("aa", big_value);
3696 control_frame.reset(framer.SerializeSynStream(syn_stream));
3697 EXPECT_TRUE(control_frame.get() != NULL);
3698 EXPECT_EQ(TestSpdyVisitor::sent_control_frame_max_size(),
3699 control_frame->size());
3701 TestSpdyVisitor visitor(spdy_version_);
3702 visitor.SimulateInFramer(
3703 reinterpret_cast<unsigned char*>(control_frame->data()),
3704 control_frame->size());
3705 EXPECT_TRUE(visitor.header_buffer_valid_);
3706 EXPECT_EQ(0, visitor.error_count_);
3707 EXPECT_EQ(1, visitor.syn_frame_count_);
3708 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
3709 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
3710 EXPECT_LT(kBigValueSize, visitor.header_buffer_length_);
3713 TEST_P(SpdyFramerTest, ControlFrameMaximumSize) {
3714 if (spdy_version_ > SPDY3) {
3715 // TODO(jgraettinger): This test setup doesn't work with HPACK.
3716 return;
3718 if (spdy_version_ < SPDY3) {
3719 // Since SPDY/2 uses 16 bit header field lengths, one cannot easily create a
3720 // header frame of maximum size.
3721 return;
3723 // First find the size of the header value in order to just reach the control
3724 // frame max size.
3725 SpdyFramer framer(spdy_version_);
3726 framer.set_enable_compression(false);
3727 SpdySynStreamIR syn_stream(1);
3728 syn_stream.SetHeader("aa", "");
3729 syn_stream.set_priority(1);
3730 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSynStream(syn_stream));
3731 const size_t kBigValueSize =
3732 SpdyConstants::GetFrameMaximumSize(spdy_version_) - control_frame->size();
3734 // Create a frame at exatly that size.
3735 string big_value(kBigValueSize, 'x');
3736 syn_stream.SetHeader("aa", big_value);
3737 // Upstream branches here and wraps HTTP/2 with EXPECT_DEBUG_DFATAL. We
3738 // neither support that in Chromium, nor do we use the same DFATAL (see
3739 // SpdyFrameBuilder::WriteFramePrefix()).
3740 control_frame.reset(framer.SerializeSynStream(syn_stream));
3742 EXPECT_TRUE(control_frame.get() != NULL);
3743 EXPECT_EQ(SpdyConstants::GetFrameMaximumSize(spdy_version_),
3744 control_frame->size());
3746 TestSpdyVisitor visitor(spdy_version_);
3747 visitor.SimulateInFramer(
3748 reinterpret_cast<unsigned char*>(control_frame->data()),
3749 control_frame->size());
3750 EXPECT_TRUE(visitor.header_buffer_valid_);
3751 EXPECT_EQ(0, visitor.error_count_);
3752 EXPECT_EQ(1, visitor.syn_frame_count_);
3755 TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) {
3756 if (spdy_version_ <= SPDY3) {
3757 return;
3759 SpdyFramer framer(spdy_version_);
3760 framer.set_enable_compression(false);
3761 SpdyHeadersIR headers(1);
3762 headers.set_padding_len(256);
3764 // Exact payload length will change with HPACK, but this should be long
3765 // enough to cause an overflow.
3766 const size_t kBigValueSize = kControlFrameSizeLimit;
3767 string big_value(kBigValueSize, 'x');
3768 headers.SetHeader("aa", big_value);
3769 scoped_ptr<SpdyFrame> control_frame(framer.SerializeHeaders(headers));
3770 EXPECT_TRUE(control_frame.get() != NULL);
3771 EXPECT_GT(control_frame->size(),
3772 TestSpdyVisitor::sent_control_frame_max_size());
3774 TestSpdyVisitor visitor(spdy_version_);
3775 visitor.SimulateInFramer(
3776 reinterpret_cast<unsigned char*>(control_frame->data()),
3777 control_frame->size());
3778 EXPECT_TRUE(visitor.header_buffer_valid_);
3779 EXPECT_EQ(0, visitor.error_count_);
3780 EXPECT_EQ(1, visitor.headers_frame_count_);
3781 EXPECT_EQ(16, visitor.continuation_count_);
3782 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
3785 TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) {
3786 if (spdy_version_ <= SPDY3) {
3787 return;
3789 SpdyFramer framer(spdy_version_);
3790 framer.set_enable_compression(false);
3791 SpdyPushPromiseIR push_promise(1, 2);
3792 push_promise.set_padding_len(256);
3794 // Exact payload length will change with HPACK, but this should be long
3795 // enough to cause an overflow.
3796 const size_t kBigValueSize = kControlFrameSizeLimit;
3797 string big_value(kBigValueSize, 'x');
3798 push_promise.SetHeader("aa", big_value);
3799 scoped_ptr<SpdyFrame> control_frame(
3800 framer.SerializePushPromise(push_promise));
3801 EXPECT_TRUE(control_frame.get() != NULL);
3802 EXPECT_GT(control_frame->size(),
3803 TestSpdyVisitor::sent_control_frame_max_size());
3805 TestSpdyVisitor visitor(spdy_version_);
3806 visitor.SimulateInFramer(
3807 reinterpret_cast<unsigned char*>(control_frame->data()),
3808 control_frame->size());
3809 EXPECT_TRUE(visitor.header_buffer_valid_);
3810 EXPECT_EQ(0, visitor.error_count_);
3811 EXPECT_EQ(1, visitor.push_promise_frame_count_);
3812 EXPECT_EQ(16, visitor.continuation_count_);
3813 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
3816 // Check that the framer stops delivering header data chunks once the visitor
3817 // declares it doesn't want any more. This is important to guard against
3818 // "zip bomb" types of attacks.
3819 TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) {
3820 const size_t kHeaderBufferChunks = 4;
3821 const size_t kHeaderBufferSize =
3822 TestSpdyVisitor::header_data_chunk_max_size() * kHeaderBufferChunks;
3823 const size_t kBigValueSize = kHeaderBufferSize * 2;
3824 string big_value(kBigValueSize, 'x');
3825 SpdyFramer framer(spdy_version_);
3826 SpdyHeadersIR headers(1);
3827 headers.set_priority(1);
3828 headers.set_fin(true);
3829 headers.SetHeader("aa", big_value);
3830 scoped_ptr<SpdyFrame> control_frame(framer.SerializeHeaders(headers));
3831 EXPECT_TRUE(control_frame.get() != NULL);
3832 TestSpdyVisitor visitor(spdy_version_);
3833 visitor.set_header_buffer_size(kHeaderBufferSize);
3834 visitor.use_compression_ = true;
3835 visitor.SimulateInFramer(
3836 reinterpret_cast<unsigned char*>(control_frame->data()),
3837 control_frame->size());
3838 EXPECT_FALSE(visitor.header_buffer_valid_);
3839 EXPECT_EQ(1, visitor.error_count_);
3840 EXPECT_EQ(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE,
3841 visitor.framer_.error_code())
3842 << SpdyFramer::ErrorCodeToString(framer.error_code());
3844 // The framer should have stoped delivering chunks after the visitor
3845 // signaled "stop" by returning false from OnControlFrameHeaderData().
3847 // control_frame_header_data_count_ depends on the random sequence
3848 // produced by rand(), so adding, removing or running single tests
3849 // alters this value. The best we can do is assert that it happens
3850 // at least kHeaderBufferChunks + 1.
3851 EXPECT_LE(kHeaderBufferChunks + 1,
3852 static_cast<unsigned>(visitor.control_frame_header_data_count_));
3853 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
3855 // The framer should not have sent half-close to the visitor.
3856 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
3859 TEST_P(SpdyFramerTest, DecompressCorruptHeaderBlock) {
3860 if (spdy_version_ > SPDY3) {
3861 // Deflate compression doesn't apply to HPACK.
3862 return;
3864 SpdyFramer framer(spdy_version_);
3865 framer.set_enable_compression(false);
3866 // Construct a SYN_STREAM control frame without compressing the header block,
3867 // and have the framer try to decompress it. This will cause the framer to
3868 // deal with a decompression error.
3869 SpdySynStreamIR syn_stream(1);
3870 syn_stream.set_priority(1);
3871 syn_stream.SetHeader("aa", "alpha beta gamma delta");
3872 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSynStream(syn_stream));
3873 TestSpdyVisitor visitor(spdy_version_);
3874 visitor.use_compression_ = true;
3875 visitor.SimulateInFramer(
3876 reinterpret_cast<unsigned char*>(control_frame->data()),
3877 control_frame->size());
3878 EXPECT_EQ(1, visitor.error_count_);
3879 EXPECT_EQ(SpdyFramer::SPDY_DECOMPRESS_FAILURE, visitor.framer_.error_code())
3880 << SpdyFramer::ErrorCodeToString(framer.error_code());
3881 EXPECT_EQ(0u, visitor.header_buffer_length_);
3884 TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) {
3885 SpdyFramer framer(spdy_version_);
3886 // Create a GoAway frame that has a few extra bytes at the end.
3887 // We create enough overhead to overflow the framer's control frame buffer.
3888 ASSERT_LE(SpdyFramerPeer::ControlFrameBufferSize(), 250u);
3889 const size_t length = SpdyFramerPeer::ControlFrameBufferSize() + 1;
3890 const unsigned char kV3FrameData[] = { // Also applies for V2.
3891 0x80, spdy_version_ch_, 0x00, 0x07,
3892 0x00, 0x00, 0x00, static_cast<unsigned char>(length),
3893 0x00, 0x00, 0x00, 0x00, // Stream ID
3894 0x00, 0x00, 0x00, 0x00, // Status
3897 // SPDY version 4 and up GOAWAY frames are only bound to a minimal length,
3898 // since it may carry opaque data. Verify that minimal length is tested.
3899 ASSERT_GT(framer.GetGoAwayMinimumSize(), framer.GetControlFrameHeaderSize());
3900 const size_t less_than_min_length =
3901 framer.GetGoAwayMinimumSize() - framer.GetControlFrameHeaderSize() - 1;
3902 ASSERT_LE(less_than_min_length, std::numeric_limits<unsigned char>::max());
3903 const unsigned char kH2FrameData[] = {
3904 0x00, 0x00, static_cast<unsigned char>(less_than_min_length), 0x07,
3905 0x00, 0x00, 0x00, 0x00,
3906 0x00, 0x00, 0x00, 0x00, // Stream Id
3907 0x00, 0x00, 0x00, 0x00, // Status
3908 0x00,
3910 const size_t pad_length =
3911 length + framer.GetControlFrameHeaderSize() -
3912 (IsHttp2() ? sizeof(kH2FrameData) : sizeof(kV3FrameData));
3913 string pad(pad_length, 'A');
3914 TestSpdyVisitor visitor(spdy_version_);
3916 if (IsHttp2()) {
3917 visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData));
3918 } else {
3919 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
3921 visitor.SimulateInFramer(
3922 reinterpret_cast<const unsigned char*>(pad.c_str()),
3923 pad.length());
3925 EXPECT_EQ(1, visitor.error_count_); // This generated an error.
3926 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME,
3927 visitor.framer_.error_code())
3928 << SpdyFramer::ErrorCodeToString(framer.error_code());
3929 EXPECT_EQ(0, visitor.goaway_count_); // Frame not parsed.
3932 TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) {
3933 SpdyFramer framer(spdy_version_);
3934 SpdySettingsIR settings_ir;
3935 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir));
3936 SetFrameLength(control_frame.get(), 0, spdy_version_);
3937 TestSpdyVisitor visitor(spdy_version_);
3938 visitor.use_compression_ = false;
3939 visitor.SimulateInFramer(
3940 reinterpret_cast<unsigned char*>(control_frame->data()),
3941 framer.GetControlFrameHeaderSize());
3942 if (spdy_version_ <= SPDY3) {
3943 // Should generate an error, since zero-len settings frames are unsupported.
3944 EXPECT_EQ(1, visitor.error_count_);
3945 } else {
3946 // Zero-len settings frames are permitted as of HTTP/2.
3947 EXPECT_EQ(0, visitor.error_count_);
3951 // Tests handling of SETTINGS frames with invalid length.
3952 TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) {
3953 SpdyFramer framer(spdy_version_);
3954 SpdySettingsIR settings_ir;
3956 // Add a setting to pad the frame so that we don't get a buffer overflow when
3957 // calling SimulateInFramer() below.
3958 settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE,
3959 false,
3960 false,
3961 0x00000002);
3962 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir));
3963 const size_t kNewLength = 14;
3964 SetFrameLength(control_frame.get(), kNewLength, spdy_version_);
3965 TestSpdyVisitor visitor(spdy_version_);
3966 visitor.use_compression_ = false;
3967 visitor.SimulateInFramer(
3968 reinterpret_cast<unsigned char*>(control_frame->data()),
3969 framer.GetControlFrameHeaderSize() + kNewLength);
3970 // Should generate an error, since its not possible to have a
3971 // settings frame of length kNewLength.
3972 EXPECT_EQ(1, visitor.error_count_);
3975 // Tests handling of SETTINGS frames larger than the frame buffer size.
3976 TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) {
3977 SpdyFramer framer(spdy_version_);
3978 SpdySettingsIR settings_ir;
3979 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 1),
3980 false, // persist
3981 false, // persisted
3983 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 2),
3984 false, // persist
3985 false, // persisted
3987 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 3),
3988 false, // persist
3989 false, // persisted
3992 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir));
3993 EXPECT_LT(SpdyFramerPeer::ControlFrameBufferSize(), control_frame->size());
3994 TestSpdyVisitor visitor(spdy_version_);
3995 visitor.use_compression_ = false;
3997 // Read all at once.
3998 visitor.SimulateInFramer(
3999 reinterpret_cast<unsigned char*>(control_frame->data()),
4000 control_frame->size());
4001 EXPECT_EQ(0, visitor.error_count_);
4002 EXPECT_EQ(3, visitor.setting_count_);
4003 if (spdy_version_ > SPDY3) {
4004 EXPECT_EQ(1, visitor.settings_ack_sent_);
4007 // Read data in small chunks.
4008 size_t framed_data = 0;
4009 size_t unframed_data = control_frame->size();
4010 size_t kReadChunkSize = 5; // Read five bytes at a time.
4011 while (unframed_data > 0) {
4012 size_t to_read = std::min(kReadChunkSize, unframed_data);
4013 visitor.SimulateInFramer(
4014 reinterpret_cast<unsigned char*>(control_frame->data() + framed_data),
4015 to_read);
4016 unframed_data -= to_read;
4017 framed_data += to_read;
4019 EXPECT_EQ(0, visitor.error_count_);
4020 EXPECT_EQ(3 * 2, visitor.setting_count_);
4021 if (spdy_version_ > SPDY3) {
4022 EXPECT_EQ(2, visitor.settings_ack_sent_);
4026 // Tests handling of SETTINGS frame with duplicate entries.
4027 TEST_P(SpdyFramerTest, ReadDuplicateSettings) {
4028 SpdyFramer framer(spdy_version_);
4030 const unsigned char kV2FrameData[] = {
4031 0x80, spdy_version_ch_, 0x00, 0x04,
4032 0x00, 0x00, 0x00, 0x1C,
4033 0x00, 0x00, 0x00, 0x03,
4034 0x01, 0x00, 0x00, 0x00, // 1st Setting
4035 0x00, 0x00, 0x00, 0x02,
4036 0x01, 0x00, 0x00, 0x00, // 2nd (duplicate) Setting
4037 0x00, 0x00, 0x00, 0x03,
4038 0x03, 0x00, 0x00, 0x00, // 3rd (unprocessed) Setting
4039 0x00, 0x00, 0x00, 0x03,
4041 const unsigned char kV3FrameData[] = {
4042 0x80, spdy_version_ch_, 0x00, 0x04,
4043 0x00, 0x00, 0x00, 0x1C,
4044 0x00, 0x00, 0x00, 0x03,
4045 0x00, 0x00, 0x00, 0x01, // 1st Setting
4046 0x00, 0x00, 0x00, 0x02,
4047 0x00, 0x00, 0x00, 0x01, // 2nd (duplicate) Setting
4048 0x00, 0x00, 0x00, 0x03,
4049 0x00, 0x00, 0x00, 0x03, // 3rd (unprocessed) Setting
4050 0x00, 0x00, 0x00, 0x03,
4052 const unsigned char kH2FrameData[] = {
4053 0x00, 0x00, 0x12, 0x04,
4054 0x00, 0x00, 0x00, 0x00,
4055 0x00, 0x00, 0x01, // 1st Setting
4056 0x00, 0x00, 0x00, 0x02,
4057 0x00, 0x01, // 2nd (duplicate) Setting
4058 0x00, 0x00, 0x00, 0x03,
4059 0x00, 0x03, // 3rd (unprocessed) Setting
4060 0x00, 0x00, 0x00, 0x03,
4063 TestSpdyVisitor visitor(spdy_version_);
4064 visitor.use_compression_ = false;
4065 if (IsSpdy2()) {
4066 visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData));
4067 } else if (IsSpdy3()) {
4068 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
4069 } else {
4070 visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData));
4073 if (!IsHttp2()) {
4074 EXPECT_EQ(1, visitor.setting_count_);
4075 EXPECT_EQ(1, visitor.error_count_);
4076 } else {
4077 // In HTTP/2, duplicate settings are allowed;
4078 // each setting replaces the previous value for that setting.
4079 EXPECT_EQ(3, visitor.setting_count_);
4080 EXPECT_EQ(0, visitor.error_count_);
4081 EXPECT_EQ(1, visitor.settings_ack_sent_);
4085 // Tests handling of SETTINGS frame with a setting we don't recognize.
4086 TEST_P(SpdyFramerTest, ReadUnknownSettingsId) {
4087 SpdyFramer framer(spdy_version_);
4089 const unsigned char kV2FrameData[] = {
4090 0x80, spdy_version_ch_, 0x00, 0x04,
4091 0x00, 0x00, 0x00, 0x1C,
4092 0x00, 0x00, 0x00, 0x01,
4093 0x10, 0x00, 0x00, 0x00, // 1st Setting
4094 0x00, 0x00, 0x00, 0x02,
4096 const unsigned char kV3FrameData[] = {
4097 0x80, spdy_version_ch_, 0x00, 0x04,
4098 0x00, 0x00, 0x00, 0x1C,
4099 0x00, 0x00, 0x00, 0x01,
4100 0x00, 0x00, 0x00, 0x10, // 1st Setting
4101 0x00, 0x00, 0x00, 0x02,
4103 const unsigned char kH2FrameData[] = {
4104 0x00, 0x00, 0x06, 0x04,
4105 0x00, 0x00, 0x00, 0x00,
4106 0x00, 0x00, 0x10, // 1st Setting
4107 0x00, 0x00, 0x00, 0x02,
4110 TestSpdyVisitor visitor(spdy_version_);
4111 visitor.use_compression_ = false;
4112 if (IsSpdy2()) {
4113 visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData));
4114 } else if (IsSpdy3()) {
4115 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
4116 } else {
4117 visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData));
4120 if (!IsHttp2()) {
4121 EXPECT_EQ(0, visitor.setting_count_);
4122 EXPECT_EQ(1, visitor.error_count_);
4123 } else {
4124 // In HTTP/2, we ignore unknown settings because of extensions.
4125 EXPECT_EQ(0, visitor.setting_count_);
4126 EXPECT_EQ(0, visitor.error_count_);
4130 // Tests handling of SETTINGS frame with entries out of order.
4131 TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) {
4132 SpdyFramer framer(spdy_version_);
4134 const unsigned char kV2FrameData[] = {
4135 0x80, spdy_version_ch_, 0x00, 0x04,
4136 0x00, 0x00, 0x00, 0x1C,
4137 0x00, 0x00, 0x00, 0x03,
4138 0x02, 0x00, 0x00, 0x00, // 1st Setting
4139 0x00, 0x00, 0x00, 0x02,
4140 0x01, 0x00, 0x00, 0x00, // 2nd (out of order) Setting
4141 0x00, 0x00, 0x00, 0x03,
4142 0x03, 0x00, 0x00, 0x00, // 3rd (unprocessed) Setting
4143 0x00, 0x00, 0x00, 0x03,
4145 const unsigned char kV3FrameData[] = {
4146 0x80, spdy_version_ch_, 0x00, 0x04,
4147 0x00, 0x00, 0x00, 0x1C,
4148 0x00, 0x00, 0x00, 0x03,
4149 0x00, 0x00, 0x00, 0x02, // 1st Setting
4150 0x00, 0x00, 0x00, 0x02,
4151 0x00, 0x00, 0x00, 0x01, // 2nd (out of order) Setting
4152 0x00, 0x00, 0x00, 0x03,
4153 0x00, 0x00, 0x01, 0x03, // 3rd (unprocessed) Setting
4154 0x00, 0x00, 0x00, 0x03,
4156 const unsigned char kH2FrameData[] = {
4157 0x00, 0x00, 0x12, 0x04,
4158 0x00, 0x00, 0x00, 0x00,
4159 0x00, 0x00, 0x02, // 1st Setting
4160 0x00, 0x00, 0x00, 0x02,
4161 0x00, 0x01, // 2nd (out of order) Setting
4162 0x00, 0x00, 0x00, 0x03,
4163 0x00, 0x03, // 3rd (unprocessed) Setting
4164 0x00, 0x00, 0x00, 0x03,
4167 TestSpdyVisitor visitor(spdy_version_);
4168 visitor.use_compression_ = false;
4169 if (IsSpdy2()) {
4170 visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData));
4171 } else if (IsSpdy3()) {
4172 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
4173 } else {
4174 visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData));
4177 if (!IsHttp2()) {
4178 EXPECT_EQ(1, visitor.setting_count_);
4179 EXPECT_EQ(1, visitor.error_count_);
4180 } else {
4181 // In HTTP/2, settings are allowed in any order.
4182 EXPECT_EQ(3, visitor.setting_count_);
4183 EXPECT_EQ(0, visitor.error_count_);
4187 TEST_P(SpdyFramerTest, ProcessSettingsAckFrame) {
4188 if (spdy_version_ <= SPDY3) {
4189 return;
4191 SpdyFramer framer(spdy_version_);
4193 const unsigned char kFrameData[] = {
4194 0x00, 0x00, 0x00, 0x04, 0x01,
4195 0x00, 0x00, 0x00, 0x00,
4198 TestSpdyVisitor visitor(spdy_version_);
4199 visitor.use_compression_ = false;
4200 visitor.SimulateInFramer(kFrameData, sizeof(kFrameData));
4202 EXPECT_EQ(0, visitor.error_count_);
4203 EXPECT_EQ(0, visitor.setting_count_);
4204 EXPECT_EQ(1, visitor.settings_ack_received_);
4207 TEST_P(SpdyFramerTest, ProcessDataFrameWithPadding) {
4208 if (spdy_version_ <= SPDY3) {
4209 return;
4212 const int kPaddingLen = 119;
4213 const char data_payload[] = "hello";
4215 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
4216 SpdyFramer framer(spdy_version_);
4217 framer.set_visitor(&visitor);
4219 SpdyDataIR data_ir(1, data_payload);
4220 data_ir.set_padding_len(kPaddingLen);
4221 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
4222 ASSERT_TRUE(frame.get() != NULL);
4224 int bytes_consumed = 0;
4226 // Send the frame header.
4227 EXPECT_CALL(visitor, OnDataFrameHeader(1,
4228 kPaddingLen + strlen(data_payload),
4229 false));
4230 CHECK_EQ(framer.GetDataFrameMinimumSize(),
4231 framer.ProcessInput(frame->data(),
4232 framer.GetDataFrameMinimumSize()));
4233 CHECK_EQ(framer.state(), SpdyFramer::SPDY_READ_DATA_FRAME_PADDING_LENGTH);
4234 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
4235 bytes_consumed += framer.GetDataFrameMinimumSize();
4237 // Send the padding length field.
4238 EXPECT_CALL(visitor, OnStreamPadding(1, 1));
4239 CHECK_EQ(1u, framer.ProcessInput(frame->data() + bytes_consumed, 1));
4240 CHECK_EQ(framer.state(), SpdyFramer::SPDY_FORWARD_STREAM_FRAME);
4241 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
4242 bytes_consumed += 1;
4244 // Send the first two bytes of the data payload, i.e., "he".
4245 EXPECT_CALL(visitor, OnStreamFrameData(1, _, 2, false));
4246 CHECK_EQ(2u, framer.ProcessInput(frame->data() + bytes_consumed, 2));
4247 CHECK_EQ(framer.state(), SpdyFramer::SPDY_FORWARD_STREAM_FRAME);
4248 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
4249 bytes_consumed += 2;
4251 // Send the rest three bytes of the data payload, i.e., "llo".
4252 EXPECT_CALL(visitor, OnStreamFrameData(1, _, 3, false));
4253 CHECK_EQ(3u, framer.ProcessInput(frame->data() + bytes_consumed, 3));
4254 CHECK_EQ(framer.state(), SpdyFramer::SPDY_CONSUME_PADDING);
4255 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
4256 bytes_consumed += 3;
4258 // Send the first 100 bytes of the padding payload.
4259 EXPECT_CALL(visitor, OnStreamPadding(1, 100));
4260 CHECK_EQ(100u, framer.ProcessInput(frame->data() + bytes_consumed, 100));
4261 CHECK_EQ(framer.state(), SpdyFramer::SPDY_CONSUME_PADDING);
4262 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
4263 bytes_consumed += 100;
4265 // Send rest of the padding payload.
4266 EXPECT_CALL(visitor, OnStreamPadding(1, 18));
4267 CHECK_EQ(18u, framer.ProcessInput(frame->data() + bytes_consumed, 18));
4268 CHECK_EQ(framer.state(), SpdyFramer::SPDY_READY_FOR_FRAME);
4269 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
4272 TEST_P(SpdyFramerTest, ReadWindowUpdate) {
4273 SpdyFramer framer(spdy_version_);
4274 scoped_ptr<SpdyFrame> control_frame(
4275 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 2)));
4276 TestSpdyVisitor visitor(spdy_version_);
4277 visitor.SimulateInFramer(
4278 reinterpret_cast<unsigned char*>(control_frame->data()),
4279 control_frame->size());
4280 EXPECT_EQ(1u, visitor.last_window_update_stream_);
4281 EXPECT_EQ(2, visitor.last_window_update_delta_);
4284 TEST_P(SpdyFramerTest, ReceiveCredentialFrame) {
4285 if (!IsSpdy3()) {
4286 return;
4288 SpdyFramer framer(spdy_version_);
4289 const unsigned char kV3FrameData[] = { // Also applies for V2.
4290 0x80, spdy_version_ch_, 0x00, 0x0A,
4291 0x00, 0x00, 0x00, 0x33,
4292 0x00, 0x03, 0x00, 0x00,
4293 0x00, 0x05, 'p', 'r',
4294 'o', 'o', 'f', 0x00,
4295 0x00, 0x00, 0x06, 'a',
4296 ' ', 'c', 'e', 'r',
4297 't', 0x00, 0x00, 0x00,
4298 0x0C, 'a', 'n', 'o',
4299 't', 'h', 'e', 'r',
4300 ' ', 'c', 'e', 'r',
4301 't', 0x00, 0x00, 0x00,
4302 0x0A, 'f', 'i', 'n',
4303 'a', 'l', ' ', 'c',
4304 'e', 'r', 't',
4306 TestSpdyVisitor visitor(spdy_version_);
4307 visitor.use_compression_ = false;
4308 visitor.SimulateInFramer(kV3FrameData, arraysize(kV3FrameData));
4309 EXPECT_EQ(0, visitor.error_count_);
4312 TEST_P(SpdyFramerTest, ReadCredentialFrameFollowedByAnotherFrame) {
4313 if (!IsSpdy3()) {
4314 return;
4316 SpdyFramer framer(spdy_version_);
4317 const unsigned char kV3FrameData[] = { // Also applies for V2.
4318 0x80, spdy_version_ch_, 0x00, 0x0A,
4319 0x00, 0x00, 0x00, 0x33,
4320 0x00, 0x03, 0x00, 0x00,
4321 0x00, 0x05, 'p', 'r',
4322 'o', 'o', 'f', 0x00,
4323 0x00, 0x00, 0x06, 'a',
4324 ' ', 'c', 'e', 'r',
4325 't', 0x00, 0x00, 0x00,
4326 0x0C, 'a', 'n', 'o',
4327 't', 'h', 'e', 'r',
4328 ' ', 'c', 'e', 'r',
4329 't', 0x00, 0x00, 0x00,
4330 0x0A, 'f', 'i', 'n',
4331 'a', 'l', ' ', 'c',
4332 'e', 'r', 't',
4334 TestSpdyVisitor visitor(spdy_version_);
4335 visitor.use_compression_ = false;
4336 string multiple_frame_data(reinterpret_cast<const char*>(kV3FrameData),
4337 arraysize(kV3FrameData));
4338 scoped_ptr<SpdyFrame> control_frame(
4339 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 2)));
4340 multiple_frame_data.append(string(control_frame->data(),
4341 control_frame->size()));
4342 visitor.SimulateInFramer(
4343 reinterpret_cast<unsigned const char*>(multiple_frame_data.data()),
4344 multiple_frame_data.length());
4345 EXPECT_EQ(0, visitor.error_count_);
4346 EXPECT_EQ(1u, visitor.last_window_update_stream_);
4347 EXPECT_EQ(2, visitor.last_window_update_delta_);
4350 TEST_P(SpdyFramerTest, ReadCompressedPushPromise) {
4351 if (spdy_version_ <= SPDY3) {
4352 return;
4355 SpdyFramer framer(spdy_version_);
4356 SpdyPushPromiseIR push_promise(42, 57);
4357 push_promise.SetHeader("foo", "bar");
4358 push_promise.SetHeader("bar", "foofoo");
4359 SpdyHeaderBlock headers = push_promise.header_block();
4360 scoped_ptr<SpdySerializedFrame> frame(
4361 framer.SerializePushPromise(push_promise));
4362 EXPECT_TRUE(frame.get() != NULL);
4363 TestSpdyVisitor visitor(spdy_version_);
4364 visitor.use_compression_ = true;
4365 visitor.SimulateInFramer(
4366 reinterpret_cast<unsigned char*>(frame->data()),
4367 frame->size());
4368 EXPECT_EQ(42u, visitor.last_push_promise_stream_);
4369 EXPECT_EQ(57u, visitor.last_push_promise_promised_stream_);
4370 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
4373 TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) {
4374 if (spdy_version_ <= SPDY3) {
4375 return;
4378 const unsigned char kInput[] = {
4379 0x00, 0x00, 0x14, 0x01, 0x08, // HEADERS: PADDED
4380 0x00, 0x00, 0x00, 0x01, // Stream 1
4381 0x03, // Padding of 3.
4382 0x00, 0x06, 'c', 'o',
4383 'o', 'k', 'i', 'e',
4384 0x07, 'f', 'o', 'o',
4385 '=', 'b', 'a', 'r',
4386 0x00, 0x00, 0x00,
4388 0x00, 0x00, 0x14, 0x09, 0x00, // CONTINUATION
4389 0x00, 0x00, 0x00, 0x01, // Stream 1
4390 0x00, 0x06, 'c', 'o',
4391 'o', 'k', 'i', 'e',
4392 0x08, 'b', 'a', 'z',
4393 '=', 'b', 'i', 'n',
4394 'g', 0x00, 0x06, 'c',
4396 0x00, 0x00, 0x12, 0x09, 0x04, // CONTINUATION: END_HEADERS
4397 0x00, 0x00, 0x00, 0x01, // Stream 1
4398 'o', 'o', 'k', 'i',
4399 'e', 0x00, 0x00, 0x04,
4400 'n', 'a', 'm', 'e',
4401 0x05, 'v', 'a', 'l',
4402 'u', 'e',
4405 TestSpdyVisitor visitor(spdy_version_);
4406 visitor.SimulateInFramer(kInput, sizeof(kInput));
4408 EXPECT_EQ(0, visitor.error_count_);
4409 EXPECT_EQ(1, visitor.headers_frame_count_);
4410 EXPECT_EQ(2, visitor.continuation_count_);
4411 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
4412 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
4414 EXPECT_THAT(visitor.headers_,
4415 testing::ElementsAre(
4416 testing::Pair("cookie", "foo=bar; baz=bing; "),
4417 testing::Pair("name", "value")));
4420 TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) {
4421 if (spdy_version_ <= SPDY3) {
4422 return;
4425 const unsigned char kInput[] = {
4426 0x00, 0x00, 0x10, 0x01, 0x01, // HEADERS: FIN
4427 0x00, 0x00, 0x00, 0x01, // Stream 1
4428 0x00, 0x06, 'c', 'o',
4429 'o', 'k', 'i', 'e',
4430 0x07, 'f', 'o', 'o',
4431 '=', 'b', 'a', 'r',
4433 0x00, 0x00, 0x14, 0x09, 0x00, // CONTINUATION
4434 0x00, 0x00, 0x00, 0x01, // Stream 1
4435 0x00, 0x06, 'c', 'o',
4436 'o', 'k', 'i', 'e',
4437 0x08, 'b', 'a', 'z',
4438 '=', 'b', 'i', 'n',
4439 'g', 0x00, 0x06, 'c',
4441 0x00, 0x00, 0x12, 0x09, 0x04, // CONTINUATION: END_HEADERS
4442 0x00, 0x00, 0x00, 0x01, // Stream 1
4443 'o', 'o', 'k', 'i',
4444 'e', 0x00, 0x00, 0x04,
4445 'n', 'a', 'm', 'e',
4446 0x05, 'v', 'a', 'l',
4447 'u', 'e',
4450 SpdyFramer framer(spdy_version_);
4451 TestSpdyVisitor visitor(spdy_version_);
4452 visitor.SimulateInFramer(kInput, sizeof(kInput));
4454 EXPECT_EQ(0, visitor.error_count_);
4455 EXPECT_EQ(1, visitor.headers_frame_count_);
4456 EXPECT_EQ(2, visitor.continuation_count_);
4457 EXPECT_EQ(1, visitor.fin_flag_count_);
4458 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
4459 EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
4461 EXPECT_THAT(visitor.headers_,
4462 testing::ElementsAre(
4463 testing::Pair("cookie", "foo=bar; baz=bing; "),
4464 testing::Pair("name", "value")));
4467 TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) {
4468 if (spdy_version_ <= SPDY3) {
4469 return;
4472 const unsigned char kInput[] = {
4473 0x00, 0x00, 0x17, 0x05, // PUSH_PROMISE
4474 0x08, 0x00, 0x00, 0x00, // PADDED
4475 0x01, 0x02, 0x00, 0x00, // Stream 1, Pad length field
4476 0x00, 0x2A, 0x00, 0x06, // Promised stream 42
4477 'c', 'o', 'o', 'k',
4478 'i', 'e', 0x07, 'f',
4479 'o', 'o', '=', 'b',
4480 'a', 'r', 0x00, 0x00,
4482 0x00, 0x00, 0x14, 0x09, // CONTINUATION
4483 0x00, 0x00, 0x00, 0x00,
4484 0x01, 0x00, 0x06, 'c', // Stream 1
4485 'o', 'o', 'k', 'i',
4486 'e', 0x08, 'b', 'a',
4487 'z', '=', 'b', 'i',
4488 'n', 'g', 0x00, 0x06,
4489 'c',
4491 0x00, 0x00, 0x12, 0x09, // CONTINUATION
4492 0x04, 0x00, 0x00, 0x00, // END_HEADERS
4493 0x01, 'o', 'o', 'k', // Stream 1
4494 'i', 'e', 0x00, 0x00,
4495 0x04, 'n', 'a', 'm',
4496 'e', 0x05, 'v', 'a',
4497 'l', 'u', 'e',
4500 SpdyFramer framer(spdy_version_);
4501 TestSpdyVisitor visitor(spdy_version_);
4502 visitor.SimulateInFramer(kInput, sizeof(kInput));
4504 EXPECT_EQ(0, visitor.error_count_);
4505 EXPECT_EQ(1u, visitor.last_push_promise_stream_);
4506 EXPECT_EQ(42u, visitor.last_push_promise_promised_stream_);
4507 EXPECT_EQ(2, visitor.continuation_count_);
4508 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
4509 EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
4511 EXPECT_THAT(visitor.headers_,
4512 testing::ElementsAre(
4513 testing::Pair("cookie", "foo=bar; baz=bing; "),
4514 testing::Pair("name", "value")));
4517 TEST_P(SpdyFramerTest, ReadContinuationWithWrongStreamId) {
4518 if (spdy_version_ <= SPDY3) {
4519 return;
4522 const unsigned char kInput[] = {
4523 0x00, 0x00, 0x10, 0x01, 0x00, // HEADERS
4524 0x00, 0x00, 0x00, 0x01, // Stream 1
4525 0x00, 0x06, 0x63, 0x6f,
4526 0x6f, 0x6b, 0x69, 0x65,
4527 0x07, 0x66, 0x6f, 0x6f,
4528 0x3d, 0x62, 0x61, 0x72,
4530 0x00, 0x00, 0x14, 0x09, 0x00, // CONTINUATION
4531 0x00, 0x00, 0x00, 0x02, // Stream 2
4532 0x00, 0x06, 0x63, 0x6f,
4533 0x6f, 0x6b, 0x69, 0x65,
4534 0x08, 0x62, 0x61, 0x7a,
4535 0x3d, 0x62, 0x69, 0x6e,
4536 0x67, 0x00, 0x06, 0x63,
4539 SpdyFramer framer(spdy_version_);
4540 TestSpdyVisitor visitor(spdy_version_);
4541 framer.set_visitor(&visitor);
4542 visitor.SimulateInFramer(kInput, sizeof(kInput));
4544 EXPECT_EQ(1, visitor.error_count_);
4545 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME,
4546 visitor.framer_.error_code())
4547 << SpdyFramer::ErrorCodeToString(framer.error_code());
4548 EXPECT_EQ(1, visitor.headers_frame_count_);
4549 EXPECT_EQ(0, visitor.continuation_count_);
4550 EXPECT_EQ(0u, visitor.header_buffer_length_);
4553 TEST_P(SpdyFramerTest, ReadContinuationOutOfOrder) {
4554 if (spdy_version_ <= SPDY3) {
4555 return;
4558 const unsigned char kInput[] = {
4559 0x00, 0x00, 0x18, 0x09, 0x00, // CONTINUATION
4560 0x00, 0x00, 0x00, 0x01, // Stream 1
4561 0x00, 0x06, 0x63, 0x6f,
4562 0x6f, 0x6b, 0x69, 0x65,
4563 0x07, 0x66, 0x6f, 0x6f,
4564 0x3d, 0x62, 0x61, 0x72,
4567 SpdyFramer framer(spdy_version_);
4568 TestSpdyVisitor visitor(spdy_version_);
4569 framer.set_visitor(&visitor);
4570 visitor.SimulateInFramer(kInput, sizeof(kInput));
4572 EXPECT_EQ(1, visitor.error_count_);
4573 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME,
4574 visitor.framer_.error_code())
4575 << SpdyFramer::ErrorCodeToString(framer.error_code());
4576 EXPECT_EQ(0, visitor.continuation_count_);
4577 EXPECT_EQ(0u, visitor.header_buffer_length_);
4580 TEST_P(SpdyFramerTest, ExpectContinuationReceiveData) {
4581 if (spdy_version_ <= SPDY3) {
4582 return;
4585 const unsigned char kInput[] = {
4586 0x00, 0x00, 0x10, 0x01, 0x00, // HEADERS
4587 0x00, 0x00, 0x00, 0x01, // Stream 1
4588 0x00, 0x06, 0x63, 0x6f,
4589 0x6f, 0x6b, 0x69, 0x65,
4590 0x07, 0x66, 0x6f, 0x6f,
4591 0x3d, 0x62, 0x61, 0x72,
4593 0x00, 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
4594 0x00, 0x00, 0x00, 0x04,
4595 0xde, 0xad, 0xbe, 0xef,
4598 SpdyFramer framer(spdy_version_);
4599 TestSpdyVisitor visitor(spdy_version_);
4600 framer.set_visitor(&visitor);
4601 visitor.SimulateInFramer(kInput, sizeof(kInput));
4603 EXPECT_EQ(1, visitor.error_count_);
4604 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME,
4605 visitor.framer_.error_code())
4606 << SpdyFramer::ErrorCodeToString(framer.error_code());
4607 EXPECT_EQ(1, visitor.headers_frame_count_);
4608 EXPECT_EQ(0, visitor.continuation_count_);
4609 EXPECT_EQ(0u, visitor.header_buffer_length_);
4610 EXPECT_EQ(0, visitor.data_frame_count_);
4613 TEST_P(SpdyFramerTest, ExpectContinuationReceiveControlFrame) {
4614 if (spdy_version_ <= SPDY3) {
4615 return;
4618 const unsigned char kInput[] = {
4619 0x00, 0x00, 0x18, 0x01, 0x00, // HEADERS
4620 0x00, 0x00, 0x00, 0x01, // Stream 1
4621 0x00, 0x06, 0x63, 0x6f,
4622 0x6f, 0x6b, 0x69, 0x65,
4623 0x07, 0x66, 0x6f, 0x6f,
4624 0x3d, 0x62, 0x61, 0x72,
4626 0x00, 0x00, 0x1c, 0x08, 0x00, // HEADERS
4627 0x00, 0x00, 0x00, 0x01, // Stream 1
4628 0x00, 0x06, 0x63, 0x6f, // (Note this is a valid continued encoding).
4629 0x6f, 0x6b, 0x69, 0x65,
4630 0x08, 0x62, 0x61, 0x7a,
4631 0x3d, 0x62, 0x69, 0x6e,
4632 0x67, 0x00, 0x06, 0x63,
4635 SpdyFramer framer(spdy_version_);
4636 TestSpdyVisitor visitor(spdy_version_);
4637 framer.set_visitor(&visitor);
4638 visitor.SimulateInFramer(kInput, sizeof(kInput));
4640 EXPECT_EQ(1, visitor.error_count_);
4641 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME,
4642 visitor.framer_.error_code())
4643 << SpdyFramer::ErrorCodeToString(framer.error_code());
4644 EXPECT_EQ(1, visitor.headers_frame_count_);
4645 EXPECT_EQ(0, visitor.continuation_count_);
4646 EXPECT_EQ(0u, visitor.header_buffer_length_);
4647 EXPECT_EQ(0, visitor.data_frame_count_);
4650 TEST_P(SpdyFramerTest, EndSegmentOnDataFrame) {
4651 if (spdy_version_ <= SPDY3) {
4652 return;
4654 const unsigned char kInput[] = {
4655 0x00, 0x00, 0x0c, 0x00, 0x02, // DATA: END_SEGMENT
4656 0x00, 0x00, 0x00, 0x01, // Stream 1
4657 0xde, 0xad, 0xbe, 0xef,
4658 0xde, 0xad, 0xbe, 0xef,
4659 0xde, 0xad, 0xbe, 0xef,
4662 TestSpdyVisitor visitor(spdy_version_);
4663 visitor.SimulateInFramer(kInput, sizeof(kInput));
4665 // TODO(jgraettinger): Verify END_SEGMENT when support is added.
4666 EXPECT_EQ(0, visitor.error_count_);
4667 EXPECT_EQ(12, visitor.data_bytes_);
4668 EXPECT_EQ(0, visitor.fin_frame_count_);
4669 EXPECT_EQ(0, visitor.fin_flag_count_);
4672 TEST_P(SpdyFramerTest, EndSegmentOnHeadersFrame) {
4673 if (spdy_version_ <= SPDY3) {
4674 return;
4676 const unsigned char kInput[] = {
4677 0x00, 0x00, 0x10, 0x01, 0x06, // HEADERS: END_SEGMENT | END_HEADERS
4678 0x00, 0x00, 0x00, 0x01, // Stream 1
4679 0x00, 0x06, 0x63, 0x6f,
4680 0x6f, 0x6b, 0x69, 0x65,
4681 0x07, 0x66, 0x6f, 0x6f,
4682 0x3d, 0x62, 0x61, 0x72,
4685 TestSpdyVisitor visitor(spdy_version_);
4686 visitor.SimulateInFramer(kInput, sizeof(kInput));
4688 // TODO(jgraettinger): Verify END_SEGMENT when support is added.
4689 EXPECT_EQ(0, visitor.error_count_);
4690 EXPECT_EQ(1, visitor.headers_frame_count_);
4691 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
4693 EXPECT_THAT(visitor.headers_,
4694 testing::ElementsAre(testing::Pair("cookie", "foo=bar")));
4697 TEST_P(SpdyFramerTest, ReadGarbage) {
4698 SpdyFramer framer(spdy_version_);
4699 unsigned char garbage_frame[256];
4700 memset(garbage_frame, ~0, sizeof(garbage_frame));
4701 TestSpdyVisitor visitor(spdy_version_);
4702 visitor.use_compression_ = false;
4703 visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame));
4704 EXPECT_EQ(1, visitor.error_count_);
4707 TEST_P(SpdyFramerTest, ReadUnknownExtensionFrame) {
4708 if (spdy_version_ <= SPDY3) {
4709 return;
4711 SpdyFramer framer(spdy_version_);
4713 // The unrecognized frame type should still have a valid length.
4714 const unsigned char unknown_frame[] = {
4715 0x00, 0x00, 0x08, 0xff, 0xff,
4716 0xff, 0xff, 0xff, 0xff,
4717 0xff, 0xff, 0xff, 0xff,
4718 0xff, 0xff, 0xff, 0xff,
4720 TestSpdyVisitor visitor(spdy_version_);
4722 // Simulate the case where the stream id validation checks out.
4723 visitor.on_unknown_frame_result_ = true;
4724 visitor.use_compression_ = false;
4725 visitor.SimulateInFramer(unknown_frame, arraysize(unknown_frame));
4726 EXPECT_EQ(0, visitor.error_count_);
4728 // Follow it up with a valid control frame to make sure we handle
4729 // subsequent frames correctly.
4730 SpdySettingsIR settings_ir;
4731 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 1),
4732 false, // persist
4733 false, // persisted
4734 10);
4735 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir));
4736 visitor.SimulateInFramer(
4737 reinterpret_cast<unsigned char*>(control_frame->data()),
4738 control_frame->size());
4739 EXPECT_EQ(0, visitor.error_count_);
4740 EXPECT_EQ(1u, static_cast<unsigned>(visitor.setting_count_));
4741 EXPECT_EQ(1u, static_cast<unsigned>(visitor.settings_ack_sent_));
4744 TEST_P(SpdyFramerTest, ReadGarbageWithValidLength) {
4745 if (!IsHttp2()) {
4746 return;
4748 SpdyFramer framer(spdy_version_);
4749 const unsigned char kFrameData[] = {
4750 0x00, 0x00, 0x08, 0xff, 0xff,
4751 0xff, 0xff, 0xff, 0xff,
4752 0xff, 0xff, 0xff, 0xff,
4753 0xff, 0xff, 0xff, 0xff,
4755 TestSpdyVisitor visitor(spdy_version_);
4756 visitor.use_compression_ = false;
4757 visitor.SimulateInFramer(kFrameData, arraysize(kFrameData));
4758 EXPECT_EQ(1, visitor.error_count_);
4761 TEST_P(SpdyFramerTest, ReadGarbageWithValidVersion) {
4762 if (IsHttp2()) {
4763 // Not valid for HTTP/2 since there is no version field.
4764 return;
4766 SpdyFramer framer(spdy_version_);
4767 const unsigned char kFrameData[] = {
4768 0x80, spdy_version_ch_, 0xff, 0xff,
4769 0xff, 0xff, 0xff, 0xff,
4771 TestSpdyVisitor visitor(spdy_version_);
4772 visitor.use_compression_ = false;
4773 visitor.SimulateInFramer(kFrameData, arraysize(kFrameData));
4774 EXPECT_EQ(1, visitor.error_count_);
4777 TEST_P(SpdyFramerTest, ReadGarbageHPACKEncoding) {
4778 if (spdy_version_ <= SPDY3) {
4779 return;
4781 const unsigned char kInput[] = {
4782 0x00, 0x12, 0x01, 0x04, // HEADER: END_HEADERS
4783 0x00, 0x00, 0x00, 0x01, // Stream 1
4784 0xef, 0xef, 0xff, 0xff,
4785 0xff, 0xff, 0xff, 0xff,
4786 0xff, 0xff, 0xff, 0xff,
4787 0xff, 0xff, 0xff, 0xff,
4788 0xff, 0xff,
4791 TestSpdyVisitor visitor(spdy_version_);
4792 visitor.SimulateInFramer(kInput, arraysize(kInput));
4793 EXPECT_EQ(1, visitor.error_count_);
4796 TEST_P(SpdyFramerTest, SizesTest) {
4797 SpdyFramer framer(spdy_version_);
4798 if (IsHttp2()) {
4799 EXPECT_EQ(9u, framer.GetDataFrameMinimumSize());
4800 EXPECT_EQ(9u, framer.GetControlFrameHeaderSize());
4801 EXPECT_EQ(14u, framer.GetSynStreamMinimumSize());
4802 EXPECT_EQ(9u, framer.GetSynReplyMinimumSize());
4803 EXPECT_EQ(13u, framer.GetRstStreamMinimumSize());
4804 EXPECT_EQ(9u, framer.GetSettingsMinimumSize());
4805 EXPECT_EQ(17u, framer.GetPingSize());
4806 EXPECT_EQ(17u, framer.GetGoAwayMinimumSize());
4807 EXPECT_EQ(9u, framer.GetHeadersMinimumSize());
4808 EXPECT_EQ(13u, framer.GetWindowUpdateSize());
4809 EXPECT_EQ(9u, framer.GetBlockedSize());
4810 EXPECT_EQ(13u, framer.GetPushPromiseMinimumSize());
4811 EXPECT_EQ(11u, framer.GetAltSvcMinimumSize());
4812 EXPECT_EQ(9u, framer.GetFrameMinimumSize());
4813 EXPECT_EQ(16393u, framer.GetFrameMaximumSize());
4814 EXPECT_EQ(16384u, framer.GetDataFrameMaximumPayload());
4815 } else {
4816 EXPECT_EQ(8u, framer.GetDataFrameMinimumSize());
4817 EXPECT_EQ(8u, framer.GetControlFrameHeaderSize());
4818 EXPECT_EQ(18u, framer.GetSynStreamMinimumSize());
4819 EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetSynReplyMinimumSize());
4820 EXPECT_EQ(16u, framer.GetRstStreamMinimumSize());
4821 EXPECT_EQ(12u, framer.GetSettingsMinimumSize());
4822 EXPECT_EQ(12u, framer.GetPingSize());
4823 EXPECT_EQ(IsSpdy2() ? 12u : 16u, framer.GetGoAwayMinimumSize());
4824 EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetHeadersMinimumSize());
4825 EXPECT_EQ(16u, framer.GetWindowUpdateSize());
4826 EXPECT_EQ(8u, framer.GetFrameMinimumSize());
4827 EXPECT_EQ(16777223u, framer.GetFrameMaximumSize());
4828 EXPECT_EQ(16777215u, framer.GetDataFrameMaximumPayload());
4832 TEST_P(SpdyFramerTest, StateToStringTest) {
4833 EXPECT_STREQ("ERROR",
4834 SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR));
4835 EXPECT_STREQ("FRAME_COMPLETE",
4836 SpdyFramer::StateToString(SpdyFramer::SPDY_FRAME_COMPLETE));
4837 EXPECT_STREQ("READY_FOR_FRAME",
4838 SpdyFramer::StateToString(SpdyFramer::SPDY_READY_FOR_FRAME));
4839 EXPECT_STREQ("READING_COMMON_HEADER",
4840 SpdyFramer::StateToString(
4841 SpdyFramer::SPDY_READING_COMMON_HEADER));
4842 EXPECT_STREQ("CONTROL_FRAME_PAYLOAD",
4843 SpdyFramer::StateToString(
4844 SpdyFramer::SPDY_CONTROL_FRAME_PAYLOAD));
4845 EXPECT_STREQ("IGNORE_REMAINING_PAYLOAD",
4846 SpdyFramer::StateToString(
4847 SpdyFramer::SPDY_IGNORE_REMAINING_PAYLOAD));
4848 EXPECT_STREQ("FORWARD_STREAM_FRAME",
4849 SpdyFramer::StateToString(
4850 SpdyFramer::SPDY_FORWARD_STREAM_FRAME));
4851 EXPECT_STREQ("SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK",
4852 SpdyFramer::StateToString(
4853 SpdyFramer::SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK));
4854 EXPECT_STREQ("SPDY_CONTROL_FRAME_HEADER_BLOCK",
4855 SpdyFramer::StateToString(
4856 SpdyFramer::SPDY_CONTROL_FRAME_HEADER_BLOCK));
4857 EXPECT_STREQ("SPDY_SETTINGS_FRAME_PAYLOAD",
4858 SpdyFramer::StateToString(
4859 SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD));
4860 EXPECT_STREQ("SPDY_ALTSVC_FRAME_PAYLOAD",
4861 SpdyFramer::StateToString(
4862 SpdyFramer::SPDY_ALTSVC_FRAME_PAYLOAD));
4863 EXPECT_STREQ("UNKNOWN_STATE",
4864 SpdyFramer::StateToString(
4865 SpdyFramer::SPDY_ALTSVC_FRAME_PAYLOAD + 1));
4868 TEST_P(SpdyFramerTest, ErrorCodeToStringTest) {
4869 EXPECT_STREQ("NO_ERROR",
4870 SpdyFramer::ErrorCodeToString(SpdyFramer::SPDY_NO_ERROR));
4871 EXPECT_STREQ("INVALID_CONTROL_FRAME",
4872 SpdyFramer::ErrorCodeToString(
4873 SpdyFramer::SPDY_INVALID_CONTROL_FRAME));
4874 EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE",
4875 SpdyFramer::ErrorCodeToString(
4876 SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE));
4877 EXPECT_STREQ("ZLIB_INIT_FAILURE",
4878 SpdyFramer::ErrorCodeToString(
4879 SpdyFramer::SPDY_ZLIB_INIT_FAILURE));
4880 EXPECT_STREQ("UNSUPPORTED_VERSION",
4881 SpdyFramer::ErrorCodeToString(
4882 SpdyFramer::SPDY_UNSUPPORTED_VERSION));
4883 EXPECT_STREQ("DECOMPRESS_FAILURE",
4884 SpdyFramer::ErrorCodeToString(
4885 SpdyFramer::SPDY_DECOMPRESS_FAILURE));
4886 EXPECT_STREQ("COMPRESS_FAILURE",
4887 SpdyFramer::ErrorCodeToString(
4888 SpdyFramer::SPDY_COMPRESS_FAILURE));
4889 EXPECT_STREQ("SPDY_INVALID_DATA_FRAME_FLAGS",
4890 SpdyFramer::ErrorCodeToString(
4891 SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS));
4892 EXPECT_STREQ("SPDY_INVALID_CONTROL_FRAME_FLAGS",
4893 SpdyFramer::ErrorCodeToString(
4894 SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS));
4895 EXPECT_STREQ("UNKNOWN_ERROR",
4896 SpdyFramer::ErrorCodeToString(SpdyFramer::LAST_ERROR));
4899 TEST_P(SpdyFramerTest, StatusCodeToStringTest) {
4900 EXPECT_STREQ("INVALID",
4901 SpdyFramer::StatusCodeToString(RST_STREAM_INVALID));
4902 EXPECT_STREQ("PROTOCOL_ERROR",
4903 SpdyFramer::StatusCodeToString(RST_STREAM_PROTOCOL_ERROR));
4904 EXPECT_STREQ("INVALID_STREAM",
4905 SpdyFramer::StatusCodeToString(RST_STREAM_INVALID_STREAM));
4906 EXPECT_STREQ("REFUSED_STREAM",
4907 SpdyFramer::StatusCodeToString(RST_STREAM_REFUSED_STREAM));
4908 EXPECT_STREQ("UNSUPPORTED_VERSION",
4909 SpdyFramer::StatusCodeToString(RST_STREAM_UNSUPPORTED_VERSION));
4910 EXPECT_STREQ("CANCEL",
4911 SpdyFramer::StatusCodeToString(RST_STREAM_CANCEL));
4912 EXPECT_STREQ("INTERNAL_ERROR",
4913 SpdyFramer::StatusCodeToString(RST_STREAM_INTERNAL_ERROR));
4914 EXPECT_STREQ("FLOW_CONTROL_ERROR",
4915 SpdyFramer::StatusCodeToString(RST_STREAM_FLOW_CONTROL_ERROR));
4916 EXPECT_STREQ("UNKNOWN_STATUS",
4917 SpdyFramer::StatusCodeToString(-1));
4920 TEST_P(SpdyFramerTest, FrameTypeToStringTest) {
4921 EXPECT_STREQ("DATA",
4922 SpdyFramer::FrameTypeToString(DATA));
4923 EXPECT_STREQ("SYN_STREAM",
4924 SpdyFramer::FrameTypeToString(SYN_STREAM));
4925 EXPECT_STREQ("SYN_REPLY",
4926 SpdyFramer::FrameTypeToString(SYN_REPLY));
4927 EXPECT_STREQ("RST_STREAM",
4928 SpdyFramer::FrameTypeToString(RST_STREAM));
4929 EXPECT_STREQ("SETTINGS",
4930 SpdyFramer::FrameTypeToString(SETTINGS));
4931 EXPECT_STREQ("PING",
4932 SpdyFramer::FrameTypeToString(PING));
4933 EXPECT_STREQ("GOAWAY",
4934 SpdyFramer::FrameTypeToString(GOAWAY));
4935 EXPECT_STREQ("HEADERS",
4936 SpdyFramer::FrameTypeToString(HEADERS));
4937 EXPECT_STREQ("WINDOW_UPDATE",
4938 SpdyFramer::FrameTypeToString(WINDOW_UPDATE));
4939 EXPECT_STREQ("PUSH_PROMISE",
4940 SpdyFramer::FrameTypeToString(PUSH_PROMISE));
4941 EXPECT_STREQ("CREDENTIAL",
4942 SpdyFramer::FrameTypeToString(CREDENTIAL));
4943 EXPECT_STREQ("CONTINUATION",
4944 SpdyFramer::FrameTypeToString(CONTINUATION));
4947 TEST_P(SpdyFramerTest, CatchProbableHttpResponse) {
4948 if (IsHttp2()) {
4949 // TODO(hkhalil): catch probable HTTP response in HTTP/2?
4950 return;
4953 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
4954 SpdyFramer framer(spdy_version_);
4955 framer.set_visitor(&visitor);
4957 EXPECT_CALL(visitor, OnError(_));
4958 framer.ProcessInput("HTTP/1.1", 8);
4959 EXPECT_TRUE(framer.probable_http_response());
4960 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
4961 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code())
4962 << SpdyFramer::ErrorCodeToString(framer.error_code());
4965 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
4966 SpdyFramer framer(spdy_version_);
4967 framer.set_visitor(&visitor);
4969 EXPECT_CALL(visitor, OnError(_));
4970 framer.ProcessInput("HTTP/1.0", 8);
4971 EXPECT_TRUE(framer.probable_http_response());
4972 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
4973 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code())
4974 << SpdyFramer::ErrorCodeToString(framer.error_code());
4978 TEST_P(SpdyFramerTest, DataFrameFlagsV2V3) {
4979 if (spdy_version_ > SPDY3) {
4980 return;
4983 uint8 flags = 0;
4984 do {
4985 SCOPED_TRACE(testing::Message() << "Flags " << flags);
4987 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
4988 SpdyFramer framer(spdy_version_);
4989 framer.set_visitor(&visitor);
4991 SpdyDataIR data_ir(1, "hello");
4992 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
4993 SetFrameFlags(frame.get(), flags, spdy_version_);
4995 if (flags & ~DATA_FLAG_FIN) {
4996 EXPECT_CALL(visitor, OnError(_));
4997 } else {
4998 EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN));
4999 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false));
5000 if (flags & DATA_FLAG_FIN) {
5001 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
5005 framer.ProcessInput(frame->data(), frame->size());
5006 if (flags & ~DATA_FLAG_FIN) {
5007 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5008 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS,
5009 framer.error_code())
5010 << SpdyFramer::ErrorCodeToString(framer.error_code());
5011 } else {
5012 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5013 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5014 << SpdyFramer::ErrorCodeToString(framer.error_code());
5016 } while (++flags != 0);
5019 TEST_P(SpdyFramerTest, DataFrameFlagsV4) {
5020 if (spdy_version_ <= SPDY3) {
5021 return;
5024 uint8 valid_data_flags = DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT |
5025 DATA_FLAG_PADDED;
5027 uint8 flags = 0;
5028 do {
5029 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5031 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5032 SpdyFramer framer(spdy_version_);
5033 framer.set_visitor(&visitor);
5035 SpdyDataIR data_ir(1, "hello");
5036 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
5037 SetFrameFlags(frame.get(), flags, spdy_version_);
5039 if (flags & ~valid_data_flags) {
5040 EXPECT_CALL(visitor, OnError(_));
5041 } else {
5042 EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN));
5043 if (flags & DATA_FLAG_PADDED) {
5044 // The first byte of payload is parsed as padding length.
5045 EXPECT_CALL(visitor, OnStreamPadding(_, 1));
5046 // Expect Error since the frame ends prematurely.
5047 EXPECT_CALL(visitor, OnError(_));
5048 } else {
5049 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false));
5050 if (flags & DATA_FLAG_FIN) {
5051 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
5056 framer.ProcessInput(frame->data(), frame->size());
5057 if ((flags & ~valid_data_flags) || (flags & DATA_FLAG_PADDED)) {
5058 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5059 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code())
5060 << SpdyFramer::ErrorCodeToString(framer.error_code());
5061 } else {
5062 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5063 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5064 << SpdyFramer::ErrorCodeToString(framer.error_code());
5066 } while (++flags != 0);
5069 TEST_P(SpdyFramerTest, SynStreamFrameFlags) {
5070 if (!IsSpdy2() && !IsSpdy3()) {
5071 // SYN_STREAM not supported in SPDY>3
5072 return;
5074 uint8 flags = 0;
5075 do {
5076 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5078 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5079 testing::StrictMock<test::MockDebugVisitor> debug_visitor;
5080 SpdyFramer framer(spdy_version_);
5081 framer.set_visitor(&visitor);
5082 framer.set_debug_visitor(&debug_visitor);
5084 EXPECT_CALL(debug_visitor, OnSendCompressedFrame(8, SYN_STREAM, _, _));
5086 SpdySynStreamIR syn_stream(8);
5087 syn_stream.set_associated_to_stream_id(3);
5088 syn_stream.set_priority(1);
5089 syn_stream.SetHeader("foo", "bar");
5090 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream));
5091 SetFrameFlags(frame.get(), flags, spdy_version_);
5093 if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
5094 EXPECT_CALL(visitor, OnError(_));
5095 } else {
5096 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(8, SYN_STREAM, _));
5097 EXPECT_CALL(visitor, OnSynStream(8, 3, 1, flags & CONTROL_FLAG_FIN,
5098 flags & CONTROL_FLAG_UNIDIRECTIONAL));
5099 EXPECT_CALL(visitor, OnControlFrameHeaderData(8, _, _))
5100 .WillRepeatedly(testing::Return(true));
5101 if (flags & DATA_FLAG_FIN) {
5102 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
5103 } else {
5104 // Do not close the stream if we are expecting a CONTINUATION frame.
5105 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)).Times(0);
5109 framer.ProcessInput(frame->data(), frame->size());
5110 if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
5111 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5112 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5113 framer.error_code())
5114 << SpdyFramer::ErrorCodeToString(framer.error_code());
5115 } else {
5116 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5117 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5118 << SpdyFramer::ErrorCodeToString(framer.error_code());
5120 } while (++flags != 0);
5123 TEST_P(SpdyFramerTest, SynReplyFrameFlags) {
5124 if (!IsSpdy2() && !IsSpdy3()) {
5125 // SYN_REPLY not supported in SPDY>3
5126 return;
5128 uint8 flags = 0;
5129 do {
5130 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5132 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5133 SpdyFramer framer(spdy_version_);
5134 framer.set_visitor(&visitor);
5136 SpdySynReplyIR syn_reply(37);
5137 syn_reply.SetHeader("foo", "bar");
5138 scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply));
5139 SetFrameFlags(frame.get(), flags, spdy_version_);
5141 if (flags & ~CONTROL_FLAG_FIN) {
5142 EXPECT_CALL(visitor, OnError(_));
5143 } else {
5144 EXPECT_CALL(visitor, OnSynReply(37, flags & CONTROL_FLAG_FIN));
5145 EXPECT_CALL(visitor, OnControlFrameHeaderData(37, _, _))
5146 .WillRepeatedly(testing::Return(true));
5147 if (flags & DATA_FLAG_FIN) {
5148 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
5152 framer.ProcessInput(frame->data(), frame->size());
5153 if (flags & ~CONTROL_FLAG_FIN) {
5154 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5155 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5156 framer.error_code())
5157 << SpdyFramer::ErrorCodeToString(framer.error_code());
5158 } else {
5159 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5160 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5161 << SpdyFramer::ErrorCodeToString(framer.error_code());
5163 } while (++flags != 0);
5166 TEST_P(SpdyFramerTest, RstStreamFrameFlags) {
5167 uint8 flags = 0;
5168 do {
5169 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5171 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5172 SpdyFramer framer(spdy_version_);
5173 framer.set_visitor(&visitor);
5175 SpdyRstStreamIR rst_stream(13, RST_STREAM_CANCEL, "");
5176 scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream));
5177 SetFrameFlags(frame.get(), flags, spdy_version_);
5179 if (flags != 0) {
5180 EXPECT_CALL(visitor, OnError(_));
5181 } else {
5182 EXPECT_CALL(visitor, OnRstStream(13, RST_STREAM_CANCEL));
5185 framer.ProcessInput(frame->data(), frame->size());
5186 if (flags != 0) {
5187 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5188 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5189 framer.error_code())
5190 << SpdyFramer::ErrorCodeToString(framer.error_code());
5191 } else {
5192 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5193 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5194 << SpdyFramer::ErrorCodeToString(framer.error_code());
5196 } while (++flags != 0);
5199 TEST_P(SpdyFramerTest, SettingsFrameFlagsOldFormat) {
5200 if (spdy_version_ > SPDY3) { return; }
5201 uint8 flags = 0;
5202 do {
5203 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5205 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5206 SpdyFramer framer(spdy_version_);
5207 framer.set_visitor(&visitor);
5209 SpdySettingsIR settings_ir;
5210 settings_ir.AddSetting(SETTINGS_UPLOAD_BANDWIDTH,
5211 false,
5212 false,
5213 54321);
5214 scoped_ptr<SpdyFrame> frame(framer.SerializeSettings(settings_ir));
5215 SetFrameFlags(frame.get(), flags, spdy_version_);
5217 if (flags & ~SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) {
5218 EXPECT_CALL(visitor, OnError(_));
5219 } else {
5220 EXPECT_CALL(visitor, OnSettings(
5221 flags & SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS));
5222 EXPECT_CALL(visitor, OnSetting(SETTINGS_UPLOAD_BANDWIDTH,
5223 SETTINGS_FLAG_NONE, 54321));
5224 EXPECT_CALL(visitor, OnSettingsEnd());
5227 framer.ProcessInput(frame->data(), frame->size());
5228 if (flags & ~SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) {
5229 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5230 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5231 framer.error_code())
5232 << SpdyFramer::ErrorCodeToString(framer.error_code());
5233 } else {
5234 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5235 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5236 << SpdyFramer::ErrorCodeToString(framer.error_code());
5238 } while (++flags != 0);
5241 TEST_P(SpdyFramerTest, SettingsFrameFlags) {
5242 if (spdy_version_ <= SPDY3) { return; }
5243 uint8 flags = 0;
5244 do {
5245 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5247 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5248 SpdyFramer framer(spdy_version_);
5249 framer.set_visitor(&visitor);
5251 SpdySettingsIR settings_ir;
5252 settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 0, 0, 16);
5253 scoped_ptr<SpdyFrame> frame(framer.SerializeSettings(settings_ir));
5254 SetFrameFlags(frame.get(), flags, spdy_version_);
5256 if (flags != 0) {
5257 EXPECT_CALL(visitor, OnError(_));
5258 } else {
5259 EXPECT_CALL(visitor, OnSettings(flags & SETTINGS_FLAG_ACK));
5260 EXPECT_CALL(visitor, OnSetting(SETTINGS_INITIAL_WINDOW_SIZE, 0, 16));
5261 EXPECT_CALL(visitor, OnSettingsEnd());
5264 framer.ProcessInput(frame->data(), frame->size());
5265 if (flags & ~SETTINGS_FLAG_ACK) {
5266 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5267 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5268 framer.error_code())
5269 << SpdyFramer::ErrorCodeToString(framer.error_code());
5270 } else if (flags & SETTINGS_FLAG_ACK) {
5271 // The frame is invalid because ACK frames should have no payload.
5272 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5273 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME,
5274 framer.error_code())
5275 << SpdyFramer::ErrorCodeToString(framer.error_code());
5276 } else {
5277 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5278 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5279 << SpdyFramer::ErrorCodeToString(framer.error_code());
5281 } while (++flags != 0);
5284 TEST_P(SpdyFramerTest, GoawayFrameFlags) {
5285 uint8 flags = 0;
5286 do {
5287 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5289 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5290 SpdyFramer framer(spdy_version_);
5291 framer.set_visitor(&visitor);
5293 SpdyGoAwayIR goaway_ir(97, GOAWAY_OK, "test");
5294 scoped_ptr<SpdyFrame> frame(framer.SerializeGoAway(goaway_ir));
5295 SetFrameFlags(frame.get(), flags, spdy_version_);
5297 if (flags != 0) {
5298 EXPECT_CALL(visitor, OnError(_));
5299 } else {
5300 EXPECT_CALL(visitor, OnGoAway(97, GOAWAY_OK));
5303 framer.ProcessInput(frame->data(), frame->size());
5304 if (flags != 0) {
5305 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5306 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5307 framer.error_code())
5308 << SpdyFramer::ErrorCodeToString(framer.error_code());
5309 } else {
5310 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5311 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5312 << SpdyFramer::ErrorCodeToString(framer.error_code());
5314 } while (++flags != 0);
5317 TEST_P(SpdyFramerTest, HeadersFrameFlags) {
5318 uint8 flags = 0;
5319 do {
5320 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5322 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5323 SpdyFramer framer(spdy_version_);
5324 framer.set_visitor(&visitor);
5326 SpdyHeadersIR headers_ir(57);
5327 if (IsHttp2() && (flags & HEADERS_FLAG_PRIORITY)) {
5328 headers_ir.set_priority(3);
5329 headers_ir.set_has_priority(true);
5330 headers_ir.set_parent_stream_id(5);
5331 headers_ir.set_exclusive(true);
5333 headers_ir.SetHeader("foo", "bar");
5334 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
5335 uint8 set_flags = flags;
5336 if (IsHttp2()) {
5337 // TODO(jgraettinger): Add padding to SpdyHeadersIR,
5338 // and implement framing.
5339 set_flags &= ~HEADERS_FLAG_PADDED;
5341 SetFrameFlags(frame.get(), set_flags, spdy_version_);
5343 if (!IsHttp2() && flags & ~CONTROL_FLAG_FIN) {
5344 EXPECT_CALL(visitor, OnError(_));
5345 } else if (IsHttp2() && flags & ~(CONTROL_FLAG_FIN |
5346 HEADERS_FLAG_END_HEADERS |
5347 HEADERS_FLAG_END_SEGMENT |
5348 HEADERS_FLAG_PADDED |
5349 HEADERS_FLAG_PRIORITY)) {
5350 EXPECT_CALL(visitor, OnError(_));
5351 } else {
5352 // Expected callback values
5353 SpdyStreamId stream_id = 57;
5354 bool has_priority = false;
5355 SpdyPriority priority = 0;
5356 SpdyStreamId parent_stream_id = 0;
5357 bool exclusive = false;
5358 bool fin = flags & CONTROL_FLAG_FIN;
5359 bool end = !IsHttp2() || (flags & HEADERS_FLAG_END_HEADERS);
5360 if (spdy_version_ > SPDY3 && flags & HEADERS_FLAG_PRIORITY) {
5361 has_priority = true;
5362 priority = 3;
5363 parent_stream_id = 5;
5364 exclusive = true;
5366 EXPECT_CALL(visitor, OnHeaders(stream_id, has_priority, priority,
5367 parent_stream_id, exclusive, fin, end));
5368 EXPECT_CALL(visitor, OnControlFrameHeaderData(57, _, _))
5369 .WillRepeatedly(testing::Return(true));
5370 if (flags & DATA_FLAG_FIN &&
5371 (!IsHttp2() || flags & HEADERS_FLAG_END_HEADERS)) {
5372 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
5373 } else {
5374 // Do not close the stream if we are expecting a CONTINUATION frame.
5375 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)).Times(0);
5379 framer.ProcessInput(frame->data(), frame->size());
5380 if (!IsHttp2() && flags & ~CONTROL_FLAG_FIN) {
5381 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5382 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5383 framer.error_code())
5384 << SpdyFramer::ErrorCodeToString(framer.error_code());
5385 } else if (IsHttp2() && flags & ~(CONTROL_FLAG_FIN |
5386 HEADERS_FLAG_END_HEADERS |
5387 HEADERS_FLAG_END_SEGMENT |
5388 HEADERS_FLAG_PADDED |
5389 HEADERS_FLAG_PRIORITY)) {
5390 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5391 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5392 framer.error_code())
5393 << SpdyFramer::ErrorCodeToString(framer.error_code());
5394 } else if (IsHttp2() && ~(flags & HEADERS_FLAG_END_HEADERS)) {
5395 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5396 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5397 << SpdyFramer::ErrorCodeToString(framer.error_code());
5398 } else {
5399 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5400 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5401 << SpdyFramer::ErrorCodeToString(framer.error_code());
5403 } while (++flags != 0);
5406 TEST_P(SpdyFramerTest, PingFrameFlags) {
5407 uint8 flags = 0;
5408 do {
5409 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5411 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5412 SpdyFramer framer(spdy_version_);
5413 framer.set_visitor(&visitor);
5415 scoped_ptr<SpdyFrame> frame(framer.SerializePing(SpdyPingIR(42)));
5416 SetFrameFlags(frame.get(), flags, spdy_version_);
5418 if (spdy_version_ > SPDY3 &&
5419 flags == PING_FLAG_ACK) {
5420 EXPECT_CALL(visitor, OnPing(42, true));
5421 } else if (flags == 0) {
5422 EXPECT_CALL(visitor, OnPing(42, false));
5423 } else {
5424 EXPECT_CALL(visitor, OnError(_));
5427 framer.ProcessInput(frame->data(), frame->size());
5428 if ((spdy_version_ > SPDY3 && flags == PING_FLAG_ACK) ||
5429 flags == 0) {
5430 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5431 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5432 << SpdyFramer::ErrorCodeToString(framer.error_code());
5433 } else {
5434 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5435 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5436 framer.error_code())
5437 << SpdyFramer::ErrorCodeToString(framer.error_code());
5439 } while (++flags != 0);
5442 TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) {
5443 uint8 flags = 0;
5444 do {
5445 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5447 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5448 SpdyFramer framer(spdy_version_);
5449 framer.set_visitor(&visitor);
5451 scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate(
5452 SpdyWindowUpdateIR(4, 1024)));
5453 SetFrameFlags(frame.get(), flags, spdy_version_);
5455 if (flags != 0) {
5456 EXPECT_CALL(visitor, OnError(_));
5457 } else {
5458 EXPECT_CALL(visitor, OnWindowUpdate(4, 1024));
5461 framer.ProcessInput(frame->data(), frame->size());
5462 if (flags != 0) {
5463 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5464 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5465 framer.error_code())
5466 << SpdyFramer::ErrorCodeToString(framer.error_code());
5467 } else {
5468 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5469 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5470 << SpdyFramer::ErrorCodeToString(framer.error_code());
5472 } while (++flags != 0);
5475 TEST_P(SpdyFramerTest, PushPromiseFrameFlags) {
5476 if (spdy_version_ <= SPDY3) {
5477 return;
5480 uint8 flags = 0;
5481 do {
5482 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5484 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5485 testing::StrictMock<test::MockDebugVisitor> debug_visitor;
5486 SpdyFramer framer(spdy_version_);
5487 framer.set_visitor(&visitor);
5488 framer.set_debug_visitor(&debug_visitor);
5490 EXPECT_CALL(debug_visitor, OnSendCompressedFrame(42, PUSH_PROMISE, _, _));
5492 SpdyPushPromiseIR push_promise(42, 57);
5493 push_promise.SetHeader("foo", "bar");
5494 scoped_ptr<SpdySerializedFrame> frame(
5495 framer.SerializePushPromise(push_promise));
5496 // TODO(jgraettinger): Add padding to SpdyPushPromiseIR,
5497 // and implement framing.
5498 SetFrameFlags(frame.get(), flags & ~HEADERS_FLAG_PADDED, spdy_version_);
5500 if (flags & ~(PUSH_PROMISE_FLAG_END_PUSH_PROMISE | HEADERS_FLAG_PADDED)) {
5501 EXPECT_CALL(visitor, OnError(_));
5502 } else {
5503 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(42, PUSH_PROMISE, _));
5504 EXPECT_CALL(visitor, OnPushPromise(42, 57,
5505 flags & PUSH_PROMISE_FLAG_END_PUSH_PROMISE));
5506 EXPECT_CALL(visitor, OnControlFrameHeaderData(42, _, _))
5507 .WillRepeatedly(testing::Return(true));
5510 framer.ProcessInput(frame->data(), frame->size());
5511 if (flags & ~(PUSH_PROMISE_FLAG_END_PUSH_PROMISE | HEADERS_FLAG_PADDED)) {
5512 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5513 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5514 framer.error_code())
5515 << SpdyFramer::ErrorCodeToString(framer.error_code());
5516 } else {
5517 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5518 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5519 << SpdyFramer::ErrorCodeToString(framer.error_code());
5521 } while (++flags != 0);
5524 TEST_P(SpdyFramerTest, ContinuationFrameFlags) {
5525 if (spdy_version_ <= SPDY3) {
5526 return;
5529 uint8 flags = 0;
5530 do {
5531 SCOPED_TRACE(testing::Message() << "Flags " << flags);
5533 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5534 testing::StrictMock<test::MockDebugVisitor> debug_visitor;
5535 SpdyFramer framer(spdy_version_);
5536 framer.set_visitor(&visitor);
5537 framer.set_debug_visitor(&debug_visitor);
5539 EXPECT_CALL(debug_visitor, OnSendCompressedFrame(42, HEADERS, _, _));
5540 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(42, HEADERS, _));
5541 EXPECT_CALL(visitor, OnHeaders(42, false, 0, 0, false, false, false));
5542 EXPECT_CALL(visitor, OnControlFrameHeaderData(42, _, _))
5543 .WillRepeatedly(testing::Return(true));
5545 SpdyHeadersIR headers_ir(42);
5546 headers_ir.SetHeader("foo", "bar");
5547 scoped_ptr<SpdyFrame> frame0(framer.SerializeHeaders(headers_ir));
5548 SetFrameFlags(frame0.get(), 0, spdy_version_);
5550 SpdyContinuationIR continuation(42);
5551 continuation.SetHeader("foo", "bar");
5552 scoped_ptr<SpdySerializedFrame> frame(
5553 framer.SerializeContinuation(continuation));
5554 SetFrameFlags(frame.get(), flags, spdy_version_);
5556 if (flags & ~(HEADERS_FLAG_END_HEADERS)) {
5557 EXPECT_CALL(visitor, OnError(_));
5558 } else {
5559 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(42, CONTINUATION, _));
5560 EXPECT_CALL(visitor, OnContinuation(42,
5561 flags & HEADERS_FLAG_END_HEADERS));
5562 EXPECT_CALL(visitor, OnControlFrameHeaderData(42, _, _))
5563 .WillRepeatedly(testing::Return(true));
5566 framer.ProcessInput(frame0->data(), frame0->size());
5567 framer.ProcessInput(frame->data(), frame->size());
5568 if (flags & ~(HEADERS_FLAG_END_HEADERS)) {
5569 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5570 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
5571 framer.error_code())
5572 << SpdyFramer::ErrorCodeToString(framer.error_code());
5573 } else {
5574 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5575 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5576 << SpdyFramer::ErrorCodeToString(framer.error_code());
5578 } while (++flags != 0);
5581 // TODO(mlavan): Add TEST_P(SpdyFramerTest, AltSvcFrameFlags)
5583 // TODO(hkhalil): Add TEST_P(SpdyFramerTest, BlockedFrameFlags)
5585 TEST_P(SpdyFramerTest, EmptySynStream) {
5586 if (!IsSpdy2() && !IsSpdy3()) {
5587 // SYN_STREAM not supported in SPDY>3.
5588 return;
5590 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5591 testing::StrictMock<test::MockDebugVisitor> debug_visitor;
5592 SpdyFramer framer(spdy_version_);
5593 framer.set_visitor(&visitor);
5594 framer.set_debug_visitor(&debug_visitor);
5596 EXPECT_CALL(debug_visitor, OnSendCompressedFrame(1, SYN_STREAM, _, _));
5598 SpdySynStreamIR syn_stream(1);
5599 syn_stream.set_priority(1);
5600 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream));
5601 // Adjust size to remove the header block.
5602 SetFrameLength(
5603 frame.get(),
5604 framer.GetSynStreamMinimumSize() - framer.GetControlFrameHeaderSize(),
5605 spdy_version_);
5607 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(1, SYN_STREAM, _));
5608 EXPECT_CALL(visitor, OnSynStream(1, 0, 1, false, false));
5609 EXPECT_CALL(visitor, OnControlFrameHeaderData(1, NULL, 0));
5611 framer.ProcessInput(frame->data(), framer.GetSynStreamMinimumSize());
5612 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5613 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5614 << SpdyFramer::ErrorCodeToString(framer.error_code());
5617 TEST_P(SpdyFramerTest, SettingsFlagsAndId) {
5618 const uint32 kId = 0x020304;
5619 const uint32 kFlags = 0x01;
5620 const uint32 kWireFormat = htonl(IsSpdy2() ? 0x04030201 : 0x01020304);
5622 SettingsFlagsAndId id_and_flags =
5623 SettingsFlagsAndId::FromWireFormat(spdy_version_, kWireFormat);
5624 EXPECT_EQ(kId, id_and_flags.id());
5625 EXPECT_EQ(kFlags, id_and_flags.flags());
5626 EXPECT_EQ(kWireFormat, id_and_flags.GetWireFormat(spdy_version_));
5629 // Test handling of a RST_STREAM with out-of-bounds status codes.
5630 TEST_P(SpdyFramerTest, RstStreamStatusBounds) {
5631 const unsigned char kRstStreamStatusTooLow = 0x00;
5632 const unsigned char kRstStreamStatusTooHigh = 0xff;
5633 const unsigned char kV3RstStreamInvalid[] = {
5634 0x80, spdy_version_ch_, 0x00, 0x03,
5635 0x00, 0x00, 0x00, 0x08,
5636 0x00, 0x00, 0x00, 0x01,
5637 0x00, 0x00, 0x00, kRstStreamStatusTooLow
5639 const unsigned char kH2RstStreamInvalid[] = {
5640 0x00, 0x00, 0x04, 0x03,
5641 0x00, 0x00, 0x00, 0x00,
5642 0x01, 0x00, 0x00, 0x00,
5643 kRstStreamStatusTooLow
5646 const unsigned char kV3RstStreamNumStatusCodes[] = {
5647 0x80, spdy_version_ch_, 0x00, 0x03,
5648 0x00, 0x00, 0x00, 0x08,
5649 0x00, 0x00, 0x00, 0x01,
5650 0x00, 0x00, 0x00, kRstStreamStatusTooHigh
5652 const unsigned char kH2RstStreamNumStatusCodes[] = {
5653 0x00, 0x00, 0x04, 0x03,
5654 0x00, 0x00, 0x00, 0x00,
5655 0x01, 0x00, 0x00, 0x00,
5656 kRstStreamStatusTooHigh
5659 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5660 SpdyFramer framer(spdy_version_);
5661 framer.set_visitor(&visitor);
5663 if (IsHttp2()) {
5664 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INTERNAL_ERROR));
5665 framer.ProcessInput(reinterpret_cast<const char*>(kH2RstStreamInvalid),
5666 arraysize(kH2RstStreamInvalid));
5667 } else {
5668 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
5669 framer.ProcessInput(reinterpret_cast<const char*>(kV3RstStreamInvalid),
5670 arraysize(kV3RstStreamInvalid));
5672 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5673 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5674 << SpdyFramer::ErrorCodeToString(framer.error_code());
5677 framer.Reset();
5679 if (IsHttp2()) {
5680 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INTERNAL_ERROR));
5681 framer.ProcessInput(
5682 reinterpret_cast<const char*>(kH2RstStreamNumStatusCodes),
5683 arraysize(kH2RstStreamNumStatusCodes));
5684 } else {
5685 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
5686 framer.ProcessInput(
5687 reinterpret_cast<const char*>(kV3RstStreamNumStatusCodes),
5688 arraysize(kV3RstStreamNumStatusCodes));
5690 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5691 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5692 << SpdyFramer::ErrorCodeToString(framer.error_code());
5695 // Test handling of GOAWAY frames with out-of-bounds status code.
5696 TEST_P(SpdyFramerTest, GoAwayStatusBounds) {
5697 if (spdy_version_ <= SPDY2) {
5698 return;
5700 SpdyFramer framer(spdy_version_);
5702 const unsigned char kV3FrameData[] = {
5703 0x80, spdy_version_ch_, 0x00, 0x07,
5704 0x00, 0x00, 0x00, 0x08,
5705 0x00, 0x00, 0x00, 0x01, // Stream Id
5706 0xff, 0xff, 0xff, 0xff, // Status
5708 const unsigned char kH2FrameData[] = {
5709 0x00, 0x00, 0x0a, 0x07,
5710 0x00, 0x00, 0x00, 0x00,
5711 0x00, 0x00, 0x00, 0x00, // Stream id
5712 0x01, 0xff, 0xff, 0xff, // Status
5713 0xff, 0x47, 0x41, // Opaque Description
5715 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5716 framer.set_visitor(&visitor);
5718 if (IsSpdy3()) {
5719 EXPECT_CALL(visitor, OnGoAway(1, GOAWAY_OK));
5720 framer.ProcessInput(reinterpret_cast<const char*>(kV3FrameData),
5721 arraysize(kV3FrameData));
5722 } else {
5723 EXPECT_CALL(visitor, OnGoAway(1, GOAWAY_INTERNAL_ERROR));
5724 framer.ProcessInput(reinterpret_cast<const char*>(kH2FrameData),
5725 arraysize(kH2FrameData));
5727 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5728 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5729 << SpdyFramer::ErrorCodeToString(framer.error_code());
5732 // Tests handling of a GOAWAY frame with out-of-bounds stream ID.
5733 TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) {
5734 const unsigned char kV2FrameData[] = {
5735 0x80, spdy_version_ch_, 0x00, 0x07,
5736 0x00, 0x00, 0x00, 0x04,
5737 0xff, 0xff, 0xff, 0xff,
5739 const unsigned char kV3FrameData[] = {
5740 0x80, spdy_version_ch_, 0x00, 0x07,
5741 0x00, 0x00, 0x00, 0x08,
5742 0xff, 0xff, 0xff, 0xff,
5743 0x00, 0x00, 0x00, 0x00,
5745 const unsigned char kH2FrameData[] = {
5746 0x00, 0x00, 0x08, 0x07,
5747 0x00, 0x00, 0x00, 0x00,
5748 0x00, 0xff, 0xff, 0xff,
5749 0xff, 0x00, 0x00, 0x00,
5750 0x00,
5753 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5754 SpdyFramer framer(spdy_version_);
5755 framer.set_visitor(&visitor);
5757 EXPECT_CALL(visitor, OnGoAway(0x7fffffff, GOAWAY_OK));
5758 if (IsSpdy2()) {
5759 framer.ProcessInput(reinterpret_cast<const char*>(kV2FrameData),
5760 arraysize(kV2FrameData));
5761 } else if (IsSpdy3()) {
5762 framer.ProcessInput(reinterpret_cast<const char*>(kV3FrameData),
5763 arraysize(kV3FrameData));
5764 } else {
5765 framer.ProcessInput(reinterpret_cast<const char*>(kH2FrameData),
5766 arraysize(kH2FrameData));
5768 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5769 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5770 << SpdyFramer::ErrorCodeToString(framer.error_code());
5773 TEST_P(SpdyFramerTest, OnBlocked) {
5774 if (spdy_version_ <= SPDY3) {
5775 return;
5778 const SpdyStreamId kStreamId = 0;
5780 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5781 SpdyFramer framer(spdy_version_);
5782 framer.set_visitor(&visitor);
5784 EXPECT_CALL(visitor, OnBlocked(kStreamId));
5786 SpdyBlockedIR blocked_ir(0);
5787 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(blocked_ir));
5788 framer.ProcessInput(frame->data(), framer.GetBlockedSize());
5790 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5791 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5792 << SpdyFramer::ErrorCodeToString(framer.error_code());
5795 TEST_P(SpdyFramerTest, OnAltSvc) {
5796 if (spdy_version_ <= SPDY3) {
5797 return;
5800 const SpdyStreamId kStreamId = 1;
5802 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5803 SpdyFramer framer(spdy_version_);
5804 framer.set_visitor(&visitor);
5806 SpdyAltSvcWireFormat::AlternativeService altsvc1("pid1", "host", 443, 5, 1.0);
5807 SpdyAltSvcWireFormat::AlternativeService altsvc2("p\"=i:d", "h_\\o\"st", 123,
5808 42, 0.2);
5809 SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
5810 altsvc_vector.push_back(altsvc1);
5811 altsvc_vector.push_back(altsvc2);
5812 EXPECT_CALL(visitor,
5813 OnAltSvc(kStreamId, StringPiece("o_r|g!n"), altsvc_vector));
5815 SpdyAltSvcIR altsvc_ir(1);
5816 altsvc_ir.set_origin("o_r|g!n");
5817 altsvc_ir.add_altsvc(altsvc1);
5818 altsvc_ir.add_altsvc(altsvc2);
5819 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir));
5820 framer.ProcessInput(frame->data(), frame->size());
5822 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5823 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5824 << SpdyFramer::ErrorCodeToString(framer.error_code());
5827 TEST_P(SpdyFramerTest, OnAltSvcNoOrigin) {
5828 if (spdy_version_ <= SPDY3) {
5829 return;
5832 const SpdyStreamId kStreamId = 1;
5834 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5835 SpdyFramer framer(spdy_version_);
5836 framer.set_visitor(&visitor);
5838 SpdyAltSvcWireFormat::AlternativeService altsvc1("pid1", "host", 443, 5, 1.0);
5839 SpdyAltSvcWireFormat::AlternativeService altsvc2("p\"=i:d", "h_\\o\"st", 123,
5840 42, 0.2);
5841 SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
5842 altsvc_vector.push_back(altsvc1);
5843 altsvc_vector.push_back(altsvc2);
5844 EXPECT_CALL(visitor, OnAltSvc(kStreamId, StringPiece(""), altsvc_vector));
5846 SpdyAltSvcIR altsvc_ir(1);
5847 altsvc_ir.add_altsvc(altsvc1);
5848 altsvc_ir.add_altsvc(altsvc2);
5849 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir));
5850 framer.ProcessInput(frame->data(), frame->size());
5852 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5853 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5854 << SpdyFramer::ErrorCodeToString(framer.error_code());
5857 TEST_P(SpdyFramerTest, OnAltSvcEmptyProtocolId) {
5858 if (spdy_version_ <= SPDY3) {
5859 return;
5862 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5863 SpdyFramer framer(spdy_version_);
5864 framer.set_visitor(&visitor);
5866 EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
5868 SpdyAltSvcIR altsvc_ir(1);
5869 altsvc_ir.set_origin("o1");
5870 altsvc_ir.add_altsvc(
5871 SpdyAltSvcWireFormat::AlternativeService("pid1", "host", 443, 5, 1.0));
5872 altsvc_ir.add_altsvc(
5873 SpdyAltSvcWireFormat::AlternativeService("", "h1", 443, 10, 1.0));
5874 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir));
5875 framer.ProcessInput(frame->data(), frame->size());
5877 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
5878 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code())
5879 << SpdyFramer::ErrorCodeToString(framer.error_code());
5882 TEST_P(SpdyFramerTest, OnAltSvcBadLengths) {
5883 if (spdy_version_ <= SPDY3) {
5884 return;
5887 const SpdyStreamId kStreamId = 1;
5889 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5890 SpdyFramer framer(spdy_version_);
5891 framer.set_visitor(&visitor);
5893 SpdyAltSvcWireFormat::AlternativeService altsvc("pid", "h1", 443, 10, 1.0);
5894 SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
5895 altsvc_vector.push_back(altsvc);
5896 EXPECT_CALL(visitor, OnAltSvc(kStreamId, StringPiece("o1"), altsvc_vector));
5898 SpdyAltSvcIR altsvc_ir(1);
5899 altsvc_ir.set_origin("o1");
5900 altsvc_ir.add_altsvc(altsvc);
5901 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir));
5902 framer.ProcessInput(frame->data(), frame->size());
5904 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5905 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5906 << SpdyFramer::ErrorCodeToString(framer.error_code());
5909 // Tests handling of ALTSVC frames delivered in small chunks.
5910 TEST_P(SpdyFramerTest, ReadChunkedAltSvcFrame) {
5911 if (spdy_version_ <= SPDY3) {
5912 return;
5915 SpdyFramer framer(spdy_version_);
5916 SpdyAltSvcIR altsvc_ir(1);
5917 SpdyAltSvcWireFormat::AlternativeService altsvc1("pid1", "host", 443, 5, 1.0);
5918 SpdyAltSvcWireFormat::AlternativeService altsvc2("p\"=i:d", "h_\\o\"st", 123,
5919 42, 0.2);
5920 altsvc_ir.add_altsvc(altsvc1);
5921 altsvc_ir.add_altsvc(altsvc2);
5923 scoped_ptr<SpdyFrame> control_frame(framer.SerializeAltSvc(altsvc_ir));
5924 TestSpdyVisitor visitor(spdy_version_);
5925 visitor.use_compression_ = false;
5927 // Read data in small chunks.
5928 size_t framed_data = 0;
5929 size_t unframed_data = control_frame->size();
5930 size_t kReadChunkSize = 5; // Read five bytes at a time.
5931 while (unframed_data > 0) {
5932 size_t to_read = std::min(kReadChunkSize, unframed_data);
5933 visitor.SimulateInFramer(
5934 reinterpret_cast<unsigned char*>(control_frame->data() + framed_data),
5935 to_read);
5936 unframed_data -= to_read;
5937 framed_data += to_read;
5939 EXPECT_EQ(0, visitor.error_count_);
5940 EXPECT_EQ(1, visitor.altsvc_count_);
5941 ASSERT_EQ(2u, visitor.test_altsvc_ir_.altsvc_vector().size());
5942 EXPECT_TRUE(visitor.test_altsvc_ir_.altsvc_vector()[0] == altsvc1);
5943 EXPECT_TRUE(visitor.test_altsvc_ir_.altsvc_vector()[1] == altsvc2);
5946 // Tests handling of PRIORITY frames.
5947 TEST_P(SpdyFramerTest, ReadPriority) {
5948 if (spdy_version_ <= SPDY3) {
5949 return;
5951 SpdyFramer framer(spdy_version_);
5952 SpdyPriorityIR priority(3, 1, 255, false);
5953 scoped_ptr<SpdySerializedFrame> frame(framer.SerializePriority(priority));
5954 testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
5955 framer.set_visitor(&visitor);
5956 EXPECT_CALL(visitor, OnPriority(3, 1, 255, false));
5957 framer.ProcessInput(frame->data(), frame->size());
5959 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
5960 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
5961 << SpdyFramer::ErrorCodeToString(framer.error_code());
5962 // TODO(mlavan): once we actually maintain a priority tree,
5963 // check that state is adjusted correctly.
5966 TEST_P(SpdyFramerTest, PriorityWeightMapping) {
5967 if (spdy_version_ <= SPDY3) {
5968 return;
5970 SpdyFramer framer(spdy_version_);
5972 EXPECT_EQ(255u, framer.MapPriorityToWeight(0));
5973 EXPECT_EQ(219u, framer.MapPriorityToWeight(1));
5974 EXPECT_EQ(182u, framer.MapPriorityToWeight(2));
5975 EXPECT_EQ(146u, framer.MapPriorityToWeight(3));
5976 EXPECT_EQ(109u, framer.MapPriorityToWeight(4));
5977 EXPECT_EQ(73u, framer.MapPriorityToWeight(5));
5978 EXPECT_EQ(36u, framer.MapPriorityToWeight(6));
5979 EXPECT_EQ(0u, framer.MapPriorityToWeight(7));
5981 EXPECT_EQ(0u, framer.MapWeightToPriority(255));
5982 EXPECT_EQ(0u, framer.MapWeightToPriority(220));
5983 EXPECT_EQ(1u, framer.MapWeightToPriority(219));
5984 EXPECT_EQ(1u, framer.MapWeightToPriority(183));
5985 EXPECT_EQ(2u, framer.MapWeightToPriority(182));
5986 EXPECT_EQ(2u, framer.MapWeightToPriority(147));
5987 EXPECT_EQ(3u, framer.MapWeightToPriority(146));
5988 EXPECT_EQ(3u, framer.MapWeightToPriority(110));
5989 EXPECT_EQ(4u, framer.MapWeightToPriority(109));
5990 EXPECT_EQ(4u, framer.MapWeightToPriority(74));
5991 EXPECT_EQ(5u, framer.MapWeightToPriority(73));
5992 EXPECT_EQ(5u, framer.MapWeightToPriority(37));
5993 EXPECT_EQ(6u, framer.MapWeightToPriority(36));
5994 EXPECT_EQ(6u, framer.MapWeightToPriority(1));
5995 EXPECT_EQ(7u, framer.MapWeightToPriority(0));
5998 // Tests handling of PRIORITY frame with incorrect size.
5999 TEST_P(SpdyFramerTest, ReadIncorrectlySizedPriority) {
6000 if (spdy_version_ <= SPDY3) {
6001 return;
6004 // PRIORITY frame of size 4, which isn't correct.
6005 const unsigned char kFrameData[] = {
6006 0x00, 0x00, 0x04, 0x02, 0x00,
6007 0x00, 0x00, 0x00, 0x03,
6008 0x00, 0x00, 0x00, 0x01,
6011 TestSpdyVisitor visitor(spdy_version_);
6012 visitor.SimulateInFramer(kFrameData, sizeof(kFrameData));
6014 EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state());
6015 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME,
6016 visitor.framer_.error_code())
6017 << SpdyFramer::ErrorCodeToString(visitor.framer_.error_code());
6020 // Test that SpdyFramer processes, by default, all passed input in one call
6021 // to ProcessInput (i.e. will not be calling set_process_single_input_frame()).
6022 TEST_P(SpdyFramerTest, ProcessAllInput) {
6023 SpdyFramer framer(spdy_version_);
6024 scoped_ptr<TestSpdyVisitor> visitor(new TestSpdyVisitor(spdy_version_));
6025 framer.set_visitor(visitor.get());
6027 // Create two input frames.
6028 SpdyHeadersIR headers(1);
6029 headers.set_priority(1);
6030 headers.SetHeader("alpha", "beta");
6031 headers.SetHeader("gamma", "charlie");
6032 headers.SetHeader("cookie", "key1=value1; key2=value2");
6033 scoped_ptr<SpdyFrame> headers_frame(framer.SerializeHeaders(headers));
6035 const char four_score[] = "Four score and seven years ago";
6036 SpdyDataIR four_score_ir(1, four_score);
6037 scoped_ptr<SpdyFrame> four_score_frame(framer.SerializeData(four_score_ir));
6039 // Put them in a single buffer (new variables here to make it easy to
6040 // change the order and type of frames).
6041 SpdyFrame* frame1 = headers_frame.get();
6042 SpdyFrame* frame2 = four_score_frame.get();
6044 const size_t frame1_size = frame1->size();
6045 const size_t frame2_size = frame2->size();
6047 LOG(INFO) << "frame1_size = " << frame1_size;
6048 LOG(INFO) << "frame2_size = " << frame2_size;
6050 string input_buffer;
6051 input_buffer.append(frame1->data(), frame1_size);
6052 input_buffer.append(frame2->data(), frame2_size);
6054 const char* buf = input_buffer.data();
6055 const size_t buf_size = input_buffer.size();
6057 LOG(INFO) << "buf_size = " << buf_size;
6059 size_t processed = framer.ProcessInput(buf, buf_size);
6060 EXPECT_EQ(buf_size, processed);
6061 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
6062 EXPECT_EQ(1, visitor->headers_frame_count_);
6063 EXPECT_EQ(1, visitor->data_frame_count_);
6064 EXPECT_EQ(strlen(four_score), static_cast<unsigned>(visitor->data_bytes_));
6067 // Test that SpdyFramer stops after processing a full frame if
6068 // process_single_input_frame is set. Input to ProcessInput has two frames, but
6069 // only processes the first when we give it the first frame split at any point,
6070 // or give it more than one frame in the input buffer.
6071 TEST_P(SpdyFramerTest, ProcessAtMostOneFrame) {
6072 SpdyFramer framer(spdy_version_);
6073 framer.set_process_single_input_frame(true);
6074 scoped_ptr<TestSpdyVisitor> visitor;
6076 // Create two input frames.
6077 const char four_score[] = "Four score and ...";
6078 SpdyDataIR four_score_ir(1, four_score);
6079 scoped_ptr<SpdyFrame> four_score_frame(framer.SerializeData(four_score_ir));
6081 SpdyHeadersIR headers(2);
6082 headers.SetHeader("alpha", "beta");
6083 headers.SetHeader("gamma", "charlie");
6084 headers.SetHeader("cookie", "key1=value1; key2=value2");
6085 scoped_ptr<SpdyFrame> headers_frame(framer.SerializeHeaders(headers));
6087 // Put them in a single buffer (new variables here to make it easy to
6088 // change the order and type of frames).
6089 SpdyFrame* frame1 = four_score_frame.get();
6090 SpdyFrame* frame2 = headers_frame.get();
6092 const size_t frame1_size = frame1->size();
6093 const size_t frame2_size = frame2->size();
6095 LOG(INFO) << "frame1_size = " << frame1_size;
6096 LOG(INFO) << "frame2_size = " << frame2_size;
6098 string input_buffer;
6099 input_buffer.append(frame1->data(), frame1_size);
6100 input_buffer.append(frame2->data(), frame2_size);
6102 const char* buf = input_buffer.data();
6103 const size_t buf_size = input_buffer.size();
6105 LOG(INFO) << "buf_size = " << buf_size;
6107 for (size_t first_size = 0; first_size <= buf_size; ++first_size) {
6108 LOG(INFO) << "first_size = " << first_size;
6109 visitor.reset(new TestSpdyVisitor(spdy_version_));
6110 framer.set_visitor(visitor.get());
6112 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
6114 size_t processed_first = framer.ProcessInput(buf, first_size);
6115 if (first_size < frame1_size) {
6116 EXPECT_EQ(first_size, processed_first);
6118 if (first_size == 0) {
6119 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
6120 } else {
6121 EXPECT_NE(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
6124 const char* rest = buf + processed_first;
6125 const size_t remaining = buf_size - processed_first;
6126 LOG(INFO) << "remaining = " << remaining;
6128 size_t processed_second = framer.ProcessInput(rest, remaining);
6130 // Redundant tests just to make it easier to think about.
6131 EXPECT_EQ(frame1_size - processed_first, processed_second);
6132 size_t processed_total = processed_first + processed_second;
6133 EXPECT_EQ(frame1_size, processed_total);
6134 } else {
6135 EXPECT_EQ(frame1_size, processed_first);
6138 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
6140 // At this point should have processed the entirety of the first frame,
6141 // and none of the second frame.
6143 EXPECT_EQ(1, visitor->data_frame_count_);
6144 EXPECT_EQ(strlen(four_score), static_cast<unsigned>(visitor->data_bytes_));
6145 EXPECT_EQ(0, visitor->headers_frame_count_);
6149 } // namespace test
6151 } // namespace net