Chromium Code Reviews| Index: net/spdy/spdy_framer_test.cc |
| =================================================================== |
| --- net/spdy/spdy_framer_test.cc (revision 125802) |
| +++ net/spdy/spdy_framer_test.cc (working copy) |
| @@ -11,13 +11,150 @@ |
| #include "net/spdy/spdy_frame_builder.h" |
| #include "testing/platform_test.h" |
| +namespace { |
| + |
| +// The current default spdy version as a byte to be included in const |
| +// byte arrays below. Name choice is unfortunate, but better to fit to four |
| +// bytes than not. |
| +unsigned char kVer = SPDY_VERSION_FOR_TESTS; |
|
Ryan Hamilton
2012/03/09 19:09:58
We need to test both spdy2 and spdy2, right? I th
ramant (doing other things)
2012/03/10 01:14:09
Done.
|
| + |
| +spdy::SpdySetting SpdySettingFromWireFormat(uint32 key, uint32 value) { |
| + return spdy::SpdySetting( |
| + spdy::SettingsFlagsAndId::FromWireFormat(SPDY_VERSION_FOR_TESTS, key), |
| + value); |
| +} |
| + |
| +} // namespace |
| + |
| namespace spdy { |
| namespace test { |
| +static const size_t kMaxDecompressedSize = 1024; |
| + |
| +class SpdyFramerTestUtil { |
| + public: |
| + // Decompress a single frame using the decompression context held by |
| + // the SpdyFramer. The implemention is meant for use only in tests |
|
Ryan Hamilton
2012/03/09 19:09:58
Since it is defined in a _test file, I don't think
ramant (doing other things)
2012/03/10 01:14:09
Done.
|
| + // and will CHECK fail if the input is anything other than a single, |
| + // well-formed compressed frame. |
| + // |
| + // Returns a new decompressed SpdyFrame. |
| + template<class SpdyFrameType> static SpdyFrame* DecompressFrame( |
| + SpdyFramer* framer, const SpdyFrameType& frame) { |
| + DecompressionVisitor visitor; |
| + framer->set_visitor(&visitor); |
| + size_t input_size = frame.length() + SpdyFrame::kHeaderSize; |
| + CHECK_EQ(input_size, framer->ProcessInput(frame.data(), input_size)); |
| + CHECK_EQ(SpdyFramer::SPDY_RESET, framer->state()); |
| + framer->set_visitor(NULL); |
| + |
| + char* buffer = visitor.ReleaseBuffer(); |
| + CHECK(buffer); |
| + SpdyFrame* decompressed_frame = new SpdyFrame(buffer, true); |
| + decompressed_frame->set_length(visitor.size() - SpdyFrame::kHeaderSize); |
| + return decompressed_frame; |
| + } |
| + |
| + class DecompressionVisitor : public SpdyFramerVisitorInterface { |
| + public: |
| + DecompressionVisitor() |
| + : buffer_(NULL), size_(0), finished_(false), allow_data_frames_(false) { |
| + } |
| + |
| + virtual void OnControl(const SpdyControlFrame* frame) { |
| + CHECK(frame->has_header_block()); |
| + CHECK(!buffer_.get()); |
| + CHECK_EQ(size_, 0u); |
| + CHECK(!finished_); |
| + |
| + int32 control_frame_header_size = 0; |
| + switch (frame->type()) { |
| + case SYN_STREAM: |
| + control_frame_header_size = SpdySynStreamControlFrame::size(); |
| + break; |
| + case SYN_REPLY: |
| + control_frame_header_size = SpdySynReplyControlFrame::size(); |
| + break; |
| + case HEADERS: |
| + control_frame_header_size = SpdyHeadersControlFrame::size(); |
| + break; |
| + default: |
| + LOG(FATAL); |
| + return; |
| + } |
| + |
| + // Allocate space for the frame, and the copy header over. |
| + buffer_.reset(new char[kMaxDecompressedSize]); |
| + memcpy(buffer_.get(), frame->data(), control_frame_header_size); |
| + size_ += control_frame_header_size; |
| + } |
| + |
| + virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id, |
| + const char* header_data, |
| + size_t len) { |
| + CHECK(buffer_.get() != NULL); |
| + CHECK_GE(kMaxDecompressedSize, size_ + len); |
| + CHECK(!finished_); |
| + if (len != 0) { |
| + memcpy(buffer_.get() + size_, header_data, len); |
| + size_ += len; |
| + } else { |
| + // Done. |
| + finished_ = true; |
| + } |
| + return true; |
| + } |
| + |
| + virtual bool OnCredentialFrameData(const char* header_data, |
| + size_t len) { |
| + LOG(FATAL) << "Unexpected CREDENTIAL Frame"; |
| + return false; |
| + } |
| + |
| + virtual void OnError(SpdyFramer* framer) { LOG(FATAL); } |
| + virtual void OnDataFrameHeader(const SpdyDataFrame* frame) { |
| + // For most tests, this class does not expect to see OnDataFrameHeader |
| + // calls. Individual tests can override this if they need to. |
| + if (!allow_data_frames_) { |
| + LOG(FATAL) << "Unexpected data frame header"; |
| + } |
| + } |
| + virtual void OnStreamFrameData(SpdyStreamId stream_id, |
| + const char* data, |
| + size_t len) { |
| + LOG(FATAL); |
| + } |
| + virtual void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) { |
| + LOG(FATAL); |
| + } |
| + |
| + char* ReleaseBuffer() { |
| + CHECK(finished_); |
| + return buffer_.release(); |
| + } |
| + |
| + size_t size() const { |
| + CHECK(finished_); |
| + return size_; |
| + } |
| + void set_allow_data_frames(bool allow) { allow_data_frames_ = allow; } |
| + |
| + private: |
| + scoped_array<char> buffer_; |
| + size_t size_; |
| + bool finished_; |
| + bool allow_data_frames_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor); |
| + }; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil); |
| +}; |
| + |
| std::string HexDumpWithMarks(const unsigned char* data, int length, |
| const bool* marks, int mark_length) { |
| - static const char kHexChars[] = "0123456789ABCDEF"; |
| + static const char kHexChars[] = "0123456789abcdef"; |
|
Ryan Hamilton
2012/03/09 19:09:58
Out of curiosity, why is this changing?
ramant (doing other things)
2012/03/10 01:14:09
Took the change as is from the server. Was trying
|
| static const int kColumns = 4; |
| const int kSizeLimit = 1024; |
| @@ -58,8 +195,8 @@ |
| const int actual_len, |
| const unsigned char* expected, |
| const int expected_len) { |
| - const int min_len = actual_len > expected_len ? expected_len : actual_len; |
| - const int max_len = actual_len > expected_len ? actual_len : expected_len; |
| + const int min_len = (actual_len > expected_len) ? expected_len : actual_len; |
|
Ryan Hamilton
2012/03/09 19:09:58
const int min_len = min(actual_len, expected_len);
ramant (doing other things)
2012/03/10 01:14:09
Done.
|
| + const int max_len = (actual_len > expected_len) ? actual_len : expected_len; |
| scoped_array<bool> marks(new bool[max_len]); |
| bool identical = (actual_len == expected_len); |
| for (int i = 0; i < min_len; ++i) { |
| @@ -89,13 +226,16 @@ |
| static const size_t kDefaultCredentialBufferSize = 16 * 1024; |
| TestSpdyVisitor() |
| - : use_compression_(false), |
| + : framer_(kVer), |
| + use_compression_(false), |
| error_count_(0), |
| syn_frame_count_(0), |
| syn_reply_frame_count_(0), |
| headers_frame_count_(0), |
| goaway_count_(0), |
| credential_count_(0), |
| + settings_frame_count_(0), |
| + setting_count_(0), |
| data_bytes_(0), |
| fin_frame_count_(0), |
| fin_flag_count_(0), |
| @@ -166,6 +306,9 @@ |
| case CREDENTIAL: |
| credential_count_++; |
| break; |
| + case SETTINGS: |
| + settings_frame_count_++; |
| + break; |
| default: |
| DLOG(FATAL); // Error! |
| } |
| @@ -173,6 +316,10 @@ |
| ++fin_flag_count_; |
| } |
| + virtual void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) { |
| + setting_count_++; |
| + } |
| + |
| bool OnControlFrameHeaderData(SpdyStreamId stream_id, |
| const char* header_data, |
| size_t len) { |
| @@ -182,7 +329,7 @@ |
| ++zero_length_control_frame_header_data_count_; |
| // Indicates end-of-header-block. |
| CHECK(header_buffer_valid_); |
| - bool parsed_headers = SpdyFramer::ParseHeaderBlockInBuffer( |
| + bool parsed_headers = framer_.ParseHeaderBlockInBuffer( |
| header_buffer_.get(), header_buffer_length_, &headers_); |
| DCHECK(parsed_headers); |
| return true; |
| @@ -197,7 +344,8 @@ |
| return true; |
| } |
| - bool OnCredentialFrameData(const char* credential_data, size_t len) { |
| + bool OnCredentialFrameData(const char* credential_data, |
| + size_t len) { |
| if (len == 0) { |
| if (!framer_.ParseCredentialData(credential_buffer_.get(), |
| credential_buffer_length_, |
| @@ -272,6 +420,8 @@ |
| int headers_frame_count_; |
| int goaway_count_; |
| int credential_count_; |
| + int settings_frame_count_; |
| + int setting_count_; |
| int data_bytes_; |
| int fin_frame_count_; // The count of RST_STREAM type frames received. |
| int fin_flag_count_; // The count of frames with the FIN flag set. |
| @@ -316,6 +466,7 @@ |
| using spdy::DATA_FLAG_FIN; |
| using spdy::SYN_STREAM; |
| using spdy::test::CompareCharArraysWithHexError; |
| +using spdy::test::SpdyFramerTestUtil; |
| using spdy::test::TestSpdyVisitor; |
| namespace spdy { |
| @@ -386,7 +537,7 @@ |
| SpdyHeaderBlock headers; |
| headers["alpha"] = "beta"; |
| headers["gamma"] = "charlie"; |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| // Encode the header block into a SynStream frame. |
| scoped_ptr<SpdySynStreamControlFrame> frame( |
| @@ -409,7 +560,7 @@ |
| SpdyHeaderBlock headers; |
| headers["alpha"] = "beta"; |
| headers["gamma"] = "charlie"; |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| // Encode the header block into a SynStream frame. |
| scoped_ptr<SpdySynStreamControlFrame> frame( |
| @@ -435,12 +586,19 @@ |
| frame.WriteUInt32(0); // Associated stream id |
| frame.WriteUInt16(0); // Priority. |
| - frame.WriteUInt16(2); // Number of headers. |
| - SpdyHeaderBlock::iterator it; |
| - frame.WriteString("gamma"); |
| - frame.WriteString("gamma"); |
| - frame.WriteString("alpha"); |
| - frame.WriteString("alpha"); |
| + if (SPDY_VERSION_FOR_TESTS < 3) { |
| + frame.WriteUInt16(2); // Number of headers. |
| + frame.WriteString("gamma"); |
| + frame.WriteString("gamma"); |
| + frame.WriteString("alpha"); |
| + frame.WriteString("alpha"); |
| + } else { |
| + frame.WriteUInt32(2); // Number of headers. |
| + frame.WriteStringPiece32("gamma"); |
| + frame.WriteStringPiece32("gamma"); |
| + frame.WriteStringPiece32("alpha"); |
| + frame.WriteStringPiece32("alpha"); |
| + } |
| // write the length |
| frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); |
| @@ -449,13 +607,84 @@ |
| SpdySynStreamControlFrame syn_frame(control_frame->data(), false); |
| std::string serialized_headers(syn_frame.header_block(), |
| syn_frame.header_block_len()); |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| framer.set_enable_compression(false); |
| EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), |
| serialized_headers.size(), |
| &new_headers)); |
| } |
| +TEST_F(SpdyFramerTest, CreateCredential) { |
| + SpdyFramer framer(kVer); |
| + |
| + { |
| + const char kDescription[] = "CREDENTIAL frame"; |
| + const unsigned char kFrameData[] = { |
| + 0x80, kVer, 0x00, 0x0A, |
| + 0x00, 0x00, 0x00, 0x33, |
| + 0x00, 0x03, 0x00, 0x00, |
| + 0x00, 0x05, 'p', 'r', |
| + 'o', 'o', 'f', 0x00, |
| + 0x00, 0x00, 0x06, 'a', |
| + ' ', 'c', 'e', 'r', |
| + 't', 0x00, 0x00, 0x00, |
| + 0x0C, 'a', 'n', 'o', |
| + 't', 'h', 'e', 'r', |
| + ' ', 'c', 'e', 'r', |
| + 't', 0x00, 0x00, 0x00, |
| + 0x0A, 'f', 'i', 'n', |
| + 'a', 'l', ' ', 'c', |
| + 'e', 'r', 't', |
| + }; |
| + SpdyCredential credential; |
| + credential.slot = 3; |
| + credential.proof = "proof"; |
| + credential.certs.push_back("a cert"); |
| + credential.certs.push_back("another cert"); |
| + credential.certs.push_back("final cert"); |
| + scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential)); |
| + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + } |
| +} |
| + |
| +TEST_F(SpdyFramerTest, ParseCredentialFrameData) { |
| + SpdyFramer framer(kVer); |
| + |
| + { |
| + unsigned char kFrameData[] = { |
| + 0x80, kVer, 0x00, 0x0A, |
| + 0x00, 0x00, 0x00, 0x33, |
| + 0x00, 0x03, 0x00, 0x00, |
| + 0x00, 0x05, 'p', 'r', |
| + 'o', 'o', 'f', 0x00, |
| + 0x00, 0x00, 0x06, 'a', |
| + ' ', 'c', 'e', 'r', |
| + 't', 0x00, 0x00, 0x00, |
| + 0x0C, 'a', 'n', 'o', |
| + 't', 'h', 'e', 'r', |
| + ' ', 'c', 'e', 'r', |
| + 't', 0x00, 0x00, 0x00, |
| + 0x0A, 'f', 'i', 'n', |
| + 'a', 'l', ' ', 'c', |
| + 'e', 'r', 't', |
| + }; |
| + SpdyCredentialControlFrame frame(reinterpret_cast<char*>(kFrameData), |
| + false); |
| + SpdyCredential credential; |
| + EXPECT_TRUE(SpdyFramer::ParseCredentialData(frame.payload(), frame.length(), |
| + &credential)); |
| + EXPECT_EQ(3u, credential.slot); |
| + EXPECT_EQ("proof", credential.proof); |
| + EXPECT_EQ("a cert", credential.certs.front()); |
| + credential.certs.erase(credential.certs.begin()); |
| + EXPECT_EQ("another cert", credential.certs.front()); |
| + credential.certs.erase(credential.certs.begin()); |
| + EXPECT_EQ("final cert", credential.certs.front()); |
| + credential.certs.erase(credential.certs.begin()); |
| + EXPECT_TRUE(credential.certs.empty()); |
| + } |
| +} |
| + |
| TEST_F(SpdyFramerTest, DuplicateHeader) { |
| // Frame builder with plentiful buffer size. |
| SpdyFrameBuilder frame(1024); |
| @@ -467,12 +696,19 @@ |
| frame.WriteUInt32(0); // associated stream id |
| frame.WriteUInt16(0); // Priority. |
| - frame.WriteUInt16(2); // Number of headers. |
| - SpdyHeaderBlock::iterator it; |
| - frame.WriteString("name"); |
| - frame.WriteString("value1"); |
| - frame.WriteString("name"); |
| - frame.WriteString("value2"); |
| + if (SPDY_VERSION_FOR_TESTS < 3) { |
| + frame.WriteUInt16(2); // Number of headers. |
| + frame.WriteString("name"); |
| + frame.WriteString("value1"); |
| + frame.WriteString("name"); |
| + frame.WriteString("value2"); |
| + } else { |
| + frame.WriteUInt32(2); // Number of headers. |
| + frame.WriteStringPiece32("name"); |
| + frame.WriteStringPiece32("value1"); |
| + frame.WriteStringPiece32("name"); |
| + frame.WriteStringPiece32("value2"); |
| + } |
| // write the length |
| frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); |
| @@ -481,7 +717,7 @@ |
| SpdySynStreamControlFrame syn_frame(control_frame->data(), false); |
| std::string serialized_headers(syn_frame.header_block(), |
| syn_frame.header_block_len()); |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| framer.set_enable_compression(false); |
| // This should fail because duplicate headers are verboten by the spec. |
| EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), |
| @@ -500,11 +736,16 @@ |
| frame.WriteUInt32(0); // associated stream id |
| frame.WriteUInt16(0); // Priority. |
| - frame.WriteUInt16(1); // Number of headers. |
| - SpdyHeaderBlock::iterator it; |
| - frame.WriteString("name"); |
| std::string value("value1\0value2"); |
| - frame.WriteString(value); |
| + if (SPDY_VERSION_FOR_TESTS < 3) { |
| + frame.WriteUInt16(1); // Number of headers. |
| + frame.WriteString("name"); |
| + frame.WriteString(value); |
| + } else { |
| + frame.WriteUInt32(1); // Number of headers. |
| + frame.WriteStringPiece32("name"); |
| + frame.WriteStringPiece32(value); |
| + } |
| // write the length |
| frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); |
| @@ -513,7 +754,7 @@ |
| SpdySynStreamControlFrame syn_frame(control_frame->data(), false); |
| std::string serialized_headers(syn_frame.header_block(), |
| syn_frame.header_block_len()); |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| framer.set_enable_compression(false); |
| EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), |
| serialized_headers.size(), |
| @@ -531,7 +772,7 @@ |
| headers["content-type"] = "text/html"; |
| headers["content-length"] = "12"; |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| framer.set_enable_compression(true); |
| scoped_ptr<SpdySynStreamControlFrame> |
| frame1(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, |
| @@ -544,10 +785,12 @@ |
| EXPECT_LE(frame2->length(), frame1->length()); |
| // Decompress the first frame |
| - scoped_ptr<SpdyFrame> frame3(framer.DecompressFrame(*frame1.get())); |
| + scoped_ptr<SpdyFrame> frame3(SpdyFramerTestUtil::DecompressFrame( |
| + &framer, *frame1.get())); |
| // Decompress the second frame |
| - scoped_ptr<SpdyFrame> frame4(framer.DecompressFrame(*frame2.get())); |
| + scoped_ptr<SpdyFrame> frame4(SpdyFramerTestUtil::DecompressFrame( |
| + &framer, *frame2.get())); |
| // Expect frames 3 & 4 to be the same. |
| EXPECT_EQ(0, |
| @@ -566,30 +809,9 @@ |
| SpdyFrame::kHeaderSize + uncompressed_frame->length())); |
| } |
| -TEST_F(SpdyFramerTest, DecompressUncompressedFrame) { |
| - SpdyHeaderBlock headers; |
| - headers["server"] = "SpdyServer 1.0"; |
| - headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; |
| - headers["status"] = "200"; |
| - headers["version"] = "HTTP/1.1"; |
| - headers["content-type"] = "text/html"; |
| - headers["content-length"] = "12"; |
| - |
| - SpdyFramer framer; |
| - framer.set_enable_compression(true); |
| - scoped_ptr<SpdySynStreamControlFrame> |
| - frame1(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false, |
| - &headers)); |
| - |
| - // Decompress the frame |
| - scoped_ptr<SpdyFrame> frame2(framer.DecompressFrame(*frame1.get())); |
| - |
| - EXPECT_EQ(NULL, frame2.get()); |
| -} |
| - |
| TEST_F(SpdyFramerTest, Basic) { |
| - const unsigned char input[] = { |
| - 0x80, 0x02, 0x00, 0x01, // SYN Stream #1 |
| + const unsigned char kV2Input[] = { |
| + 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
| 0x00, 0x00, 0x00, 0x14, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x00, |
| @@ -597,7 +819,7 @@ |
| 0x00, 0x02, 'h', 'h', |
| 0x00, 0x02, 'v', 'v', |
| - 0x80, 0x02, 0x00, 0x08, // HEADERS on Stream #1 |
| + 0x80, kVer, 0x00, 0x08, // HEADERS on Stream #1 |
| 0x00, 0x00, 0x00, 0x18, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x02, |
| @@ -608,11 +830,11 @@ |
| 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 |
| 0x00, 0x00, 0x00, 0x0c, |
| - 0xde, 0xad, 0xbe, 0xef, |
| - 0xde, 0xad, 0xbe, 0xef, |
| - 0xde, 0xad, 0xbe, 0xef, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + 0xde, 0xad, 0xbe, 0xef, |
| - 0x80, 0x02, 0x00, 0x01, // SYN Stream #3 |
| + 0x80, kVer, 0x00, 0x01, // SYN Stream #3 |
| 0x00, 0x00, 0x00, 0x0c, |
| 0x00, 0x00, 0x00, 0x03, |
| 0x00, 0x00, 0x00, 0x00, |
| @@ -620,14 +842,14 @@ |
| 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 |
| 0x00, 0x00, 0x00, 0x08, |
| - 0xde, 0xad, 0xbe, 0xef, |
| - 0xde, 0xad, 0xbe, 0xef, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + 0xde, 0xad, 0xbe, 0xef, |
| 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 |
| 0x00, 0x00, 0x00, 0x04, |
| - 0xde, 0xad, 0xbe, 0xef, |
| + 0xde, 0xad, 0xbe, 0xef, |
| - 0x80, 0x02, 0x00, 0x03, // RST_STREAM on Stream #1 |
| + 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #1 |
| 0x00, 0x00, 0x00, 0x08, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x00, |
| @@ -635,14 +857,77 @@ |
| 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 |
| 0x00, 0x00, 0x00, 0x00, |
| - 0x80, 0x02, 0x00, 0x03, // RST_STREAM on Stream #3 |
| + 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #3 |
| 0x00, 0x00, 0x00, 0x08, |
| 0x00, 0x00, 0x00, 0x03, |
| 0x00, 0x00, 0x00, 0x00, |
| }; |
| + const unsigned char kV3Input[] = { |
| + 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
| + 0x00, 0x00, 0x00, 0x1a, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x01, 0x00, 0x00, |
| + 0x00, 0x02, 'h', 'h', |
| + 0x00, 0x00, 0x00, 0x02, |
| + 'v', 'v', |
| + |
| + 0x80, kVer, 0x00, 0x08, // HEADERS on Stream #1 |
| + 0x00, 0x00, 0x00, 0x22, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x02, 0x00, 0x00, |
| + 0x00, 0x02, 'h', '2', |
| + 0x00, 0x00, 0x00, 0x02, |
| + 'v', '2', 0x00, 0x00, |
| + 0x00, 0x02, 'h', '3', |
| + 0x00, 0x00, 0x00, 0x02, |
| + 'v', '3', |
| + |
| + 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 |
| + 0x00, 0x00, 0x00, 0x0c, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + |
| + 0x80, kVer, 0x00, 0x01, // SYN Stream #3 |
| + 0x00, 0x00, 0x00, 0x0e, |
| + 0x00, 0x00, 0x00, 0x03, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x00, |
| + |
| + 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 |
| + 0x00, 0x00, 0x00, 0x08, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + |
| + 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 |
| + 0x00, 0x00, 0x00, 0x04, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + |
| + 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #1 |
| + 0x00, 0x00, 0x00, 0x08, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x00, |
| + |
| + 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 |
| + 0x00, 0x00, 0x00, 0x00, |
| + |
| + 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #3 |
| + 0x00, 0x00, 0x00, 0x08, |
| + 0x00, 0x00, 0x00, 0x03, |
| + 0x00, 0x00, 0x00, 0x00, |
| + }; |
| + |
| TestSpdyVisitor visitor; |
| - visitor.SimulateInFramer(input, sizeof(input)); |
| + if (SPDY_VERSION_FOR_TESTS < 3) { |
| + visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); |
| + } else { |
| + visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); |
| + } |
| EXPECT_EQ(0, visitor.error_count_); |
| EXPECT_EQ(2, visitor.syn_frame_count_); |
| @@ -657,8 +942,8 @@ |
| // Test that the FIN flag on a data frame signifies EOF. |
| TEST_F(SpdyFramerTest, FinOnDataFrame) { |
| - const unsigned char input[] = { |
| - 0x80, 0x02, 0x00, 0x01, // SYN Stream #1 |
| + const unsigned char kV2Input[] = { |
| + 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
| 0x00, 0x00, 0x00, 0x14, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x00, |
| @@ -666,7 +951,7 @@ |
| 0x00, 0x02, 'h', 'h', |
| 0x00, 0x02, 'v', 'v', |
| - 0x80, 0x02, 0x00, 0x02, // SYN REPLY Stream #1 |
| + 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 |
| 0x00, 0x00, 0x00, 0x10, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x01, |
| @@ -683,9 +968,43 @@ |
| 0x01, 0x00, 0x00, 0x04, |
| 0xde, 0xad, 0xbe, 0xef, |
| }; |
| + const unsigned char kV3Input[] = { |
| + 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
| + 0x00, 0x00, 0x00, 0x1a, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x01, 0x00, 0x00, |
| + 0x00, 0x02, 'h', 'h', |
| + 0x00, 0x00, 0x00, 0x02, |
| + 'v', 'v', |
| + 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 |
| + 0x00, 0x00, 0x00, 0x16, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x01, 0x00, 0x00, |
| + 0x00, 0x02, 'a', 'a', |
| + 0x00, 0x00, 0x00, 0x02, |
| + 'b', 'b', |
| + |
| + 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 |
| + 0x00, 0x00, 0x00, 0x0c, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + |
| + 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF |
| + 0x01, 0x00, 0x00, 0x04, |
| + 0xde, 0xad, 0xbe, 0xef, |
| + }; |
| + |
| TestSpdyVisitor visitor; |
| - visitor.SimulateInFramer(input, sizeof(input)); |
| + if (SPDY_VERSION_FOR_TESTS < 3) { |
| + visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); |
| + } else { |
| + visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); |
| + } |
| EXPECT_EQ(0, visitor.error_count_); |
| EXPECT_EQ(1, visitor.syn_frame_count_); |
| @@ -700,8 +1019,8 @@ |
| // Test that the FIN flag on a SYN reply frame signifies EOF. |
| TEST_F(SpdyFramerTest, FinOnSynReplyFrame) { |
| - const unsigned char input[] = { |
| - 0x80, 0x02, 0x00, 0x01, // SYN Stream #1 |
| + const unsigned char kV2Input[] = { |
| + 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
| 0x00, 0x00, 0x00, 0x14, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x00, |
| @@ -709,7 +1028,7 @@ |
| 0x00, 0x02, 'h', 'h', |
| 0x00, 0x02, 'v', 'v', |
| - 0x80, 0x02, 0x00, 0x02, // SYN REPLY Stream #1 |
| + 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 |
| 0x01, 0x00, 0x00, 0x14, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x00, |
| @@ -717,9 +1036,34 @@ |
| 0x00, 0x02, 'a', 'a', |
| 0x00, 0x02, 'b', 'b', |
| }; |
| + const unsigned char kV3Input[] = { |
| + 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
| + 0x00, 0x00, 0x00, 0x1a, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x01, 0x00, 0x00, |
| + 0x00, 0x02, 'h', 'h', |
| + 0x00, 0x00, 0x00, 0x02, |
| + 'v', 'v', |
| + 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 |
| + 0x01, 0x00, 0x00, 0x1a, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x01, 0x00, 0x00, |
| + 0x00, 0x02, 'a', 'a', |
| + 0x00, 0x00, 0x00, 0x02, |
| + 'b', 'b', |
| + }; |
| + |
| TestSpdyVisitor visitor; |
| - visitor.SimulateInFramer(input, sizeof(input)); |
| + if (SPDY_VERSION_FOR_TESTS < 3) { |
| + visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); |
| + } else { |
| + visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); |
| + } |
| EXPECT_EQ(0, visitor.error_count_); |
| EXPECT_EQ(1, visitor.syn_frame_count_); |
| @@ -733,8 +1077,8 @@ |
| } |
| TEST_F(SpdyFramerTest, HeaderCompression) { |
| - SpdyFramer send_framer; |
| - SpdyFramer recv_framer; |
| + SpdyFramer send_framer(kVer); |
| + SpdyFramer recv_framer(kVer); |
| send_framer.set_enable_compression(true); |
| recv_framer.set_enable_compression(true); |
| @@ -751,33 +1095,30 @@ |
| block[kHeader1] = kValue1; |
| block[kHeader2] = kValue2; |
| SpdyControlFlags flags(CONTROL_FLAG_NONE); |
| - scoped_ptr<spdy::SpdyFrame> syn_frame_1( |
| + scoped_ptr<SpdySynStreamControlFrame> syn_frame_1( |
| send_framer.CreateSynStream(1, 0, 0, flags, true, &block)); |
| EXPECT_TRUE(syn_frame_1.get() != NULL); |
| // SYN_STREAM #2 |
| block[kHeader3] = kValue3; |
| - scoped_ptr<spdy::SpdyFrame> syn_frame_2( |
| + scoped_ptr<SpdySynStreamControlFrame> syn_frame_2( |
| send_framer.CreateSynStream(3, 0, 0, flags, true, &block)); |
| EXPECT_TRUE(syn_frame_2.get() != NULL); |
| // Now start decompressing |
| scoped_ptr<SpdyFrame> decompressed; |
| - scoped_ptr<SpdyFrame> decompressed_syn_frame; |
| - SpdySynStreamControlFrame* syn_frame; |
| + scoped_ptr<SpdySynStreamControlFrame> syn_frame; |
| scoped_ptr<std::string> serialized_headers; |
| SpdyHeaderBlock decompressed_headers; |
| // Decompress SYN_STREAM #1 |
| - decompressed.reset(recv_framer.DecompressFrame(*syn_frame_1.get())); |
| + decompressed.reset(SpdyFramerTestUtil::DecompressFrame( |
| + &recv_framer, *syn_frame_1.get())); |
| EXPECT_TRUE(decompressed.get() != NULL); |
| EXPECT_TRUE(decompressed->is_control_frame()); |
| EXPECT_EQ(SYN_STREAM, |
| reinterpret_cast<SpdyControlFrame*>(decompressed.get())->type()); |
| - decompressed_syn_frame.reset( |
| - new SpdySynStreamControlFrame(decompressed->data(), false)); |
| - syn_frame = reinterpret_cast<SpdySynStreamControlFrame*>( |
| - decompressed_syn_frame.get()); |
| + syn_frame.reset(new SpdySynStreamControlFrame(decompressed->data(), false)); |
| serialized_headers.reset(new std::string(syn_frame->header_block(), |
| syn_frame->header_block_len())); |
| EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers->c_str(), |
| @@ -788,15 +1129,13 @@ |
| EXPECT_EQ(kValue2, decompressed_headers[kHeader2]); |
| // Decompress SYN_STREAM #2 |
| - decompressed.reset(recv_framer.DecompressFrame(*syn_frame_2.get())); |
| + decompressed.reset(SpdyFramerTestUtil::DecompressFrame( |
| + &recv_framer, *syn_frame_2.get())); |
| EXPECT_TRUE(decompressed.get() != NULL); |
| EXPECT_TRUE(decompressed->is_control_frame()); |
| EXPECT_EQ(SYN_STREAM, |
| reinterpret_cast<SpdyControlFrame*>(decompressed.get())->type()); |
| - decompressed_syn_frame.reset( |
| - new SpdySynStreamControlFrame(decompressed->data(), false)); |
| - syn_frame = reinterpret_cast<SpdySynStreamControlFrame*>( |
| - decompressed_syn_frame.get()); |
| + syn_frame.reset(new SpdySynStreamControlFrame(decompressed->data(), false)); |
| serialized_headers.reset(new std::string(syn_frame->header_block(), |
| syn_frame->header_block_len())); |
| decompressed_headers.clear(); |
| @@ -817,7 +1156,7 @@ |
| // Verify we don't leak when we leave streams unclosed |
| TEST_F(SpdyFramerTest, UnclosedStreamDataCompressors) { |
| - SpdyFramer send_framer; |
| + SpdyFramer send_framer(kVer); |
| send_framer.set_enable_compression(true); |
| @@ -830,7 +1169,7 @@ |
| block[kHeader1] = kValue1; |
| block[kHeader2] = kValue2; |
| SpdyControlFlags flags(CONTROL_FLAG_NONE); |
| - scoped_ptr<spdy::SpdyFrame> syn_frame( |
| + scoped_ptr<SpdyFrame> syn_frame( |
| send_framer.CreateSynStream(1, 0, 0, flags, true, &block)); |
| EXPECT_TRUE(syn_frame.get() != NULL); |
| @@ -838,7 +1177,7 @@ |
| scoped_ptr<SpdyFrame> send_frame( |
| send_framer.CreateDataFrame( |
| 1, bytes, arraysize(bytes), |
| - DATA_FLAG_FIN)); |
| + static_cast<SpdyDataFlags>(DATA_FLAG_FIN))); |
| EXPECT_TRUE(send_frame.get() != NULL); |
| // Run the inputs through the framer. |
| @@ -867,12 +1206,76 @@ |
| EXPECT_EQ(0, send_framer.num_stream_decompressors()); |
| } |
| +// Verify we can decompress the stream even if handed over to the |
| +// framer 1 byte at a time. |
| +TEST_F(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) { |
| + SpdyFramer send_framer(kVer); |
| + |
| + send_framer.set_enable_compression(true); |
| + |
| + const char kHeader1[] = "header1"; |
| + const char kHeader2[] = "header2"; |
| + const char kValue1[] = "value1"; |
| + const char kValue2[] = "value2"; |
| + |
| + SpdyHeaderBlock block; |
| + block[kHeader1] = kValue1; |
| + block[kHeader2] = kValue2; |
| + SpdyControlFlags flags(CONTROL_FLAG_NONE); |
| + scoped_ptr<SpdyFrame> syn_frame( |
| + send_framer.CreateSynStream(1, 0, 0, flags, true, &block)); |
| + EXPECT_TRUE(syn_frame.get() != NULL); |
| + |
| + const char bytes[] = "this is a test test test test test!"; |
| + scoped_ptr<SpdyFrame> send_frame( |
| + send_framer.CreateDataFrame( |
| + 1, bytes, arraysize(bytes), |
| + static_cast<SpdyDataFlags>(DATA_FLAG_FIN))); |
| + EXPECT_TRUE(send_frame.get() != NULL); |
| + |
| + // Run the inputs through the framer. |
| + TestSpdyVisitor visitor; |
| + visitor.use_compression_ = true; |
| + const unsigned char* data; |
| + data = reinterpret_cast<const unsigned char*>(syn_frame->data()); |
| + for (size_t idx = 0; |
| + idx < syn_frame->length() + SpdyFrame::kHeaderSize; |
| + ++idx) { |
| + visitor.SimulateInFramer(data + idx, 1); |
| + ASSERT_EQ(0, visitor.error_count_); |
| + } |
| + data = reinterpret_cast<const unsigned char*>(send_frame->data()); |
| + for (size_t idx = 0; |
| + idx < send_frame->length() + SpdyFrame::kHeaderSize; |
| + ++idx) { |
| + visitor.SimulateInFramer(data + idx, 1); |
| + ASSERT_EQ(0, visitor.error_count_); |
| + } |
| + |
| + EXPECT_EQ(0, visitor.error_count_); |
| + EXPECT_EQ(1, visitor.syn_frame_count_); |
| + EXPECT_EQ(0, visitor.syn_reply_frame_count_); |
| + EXPECT_EQ(0, visitor.headers_frame_count_); |
| + EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_)); |
| + EXPECT_EQ(0, visitor.fin_frame_count_); |
| + EXPECT_EQ(0, visitor.fin_flag_count_); |
| + EXPECT_EQ(1, visitor.zero_length_data_frame_count_); |
| + EXPECT_EQ(1, visitor.data_frame_count_); |
| + |
| + // We closed the streams, so all compressors should be down. |
| + EXPECT_EQ(0, visitor.framer_.num_stream_compressors()); |
| + EXPECT_EQ(0, visitor.framer_.num_stream_decompressors()); |
| + EXPECT_EQ(0, send_framer.num_stream_compressors()); |
| + EXPECT_EQ(0, send_framer.num_stream_decompressors()); |
| +} |
| + |
| TEST_F(SpdyFramerTest, WindowUpdateFrame) { |
| + SpdyFramer framer(kVer); |
| scoped_ptr<SpdyWindowUpdateControlFrame> window_update_frame( |
| - SpdyFramer::CreateWindowUpdate(1, 0x12345678)); |
| + framer.CreateWindowUpdate(1, 0x12345678)); |
| const unsigned char expected_data_frame[] = { |
| - 0x80, 0x02, 0x00, 0x09, |
| + 0x80, kVer, 0x00, 0x09, |
| 0x00, 0x00, 0x00, 0x08, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x12, 0x34, 0x56, 0x78 |
| @@ -884,7 +1287,7 @@ |
| } |
| TEST_F(SpdyFramerTest, CreateDataFrame) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| { |
| const char kDescription[] = "'hello' data frame, no FIN"; |
| @@ -970,7 +1373,7 @@ |
| } |
| TEST_F(SpdyFramerTest, CreateSynStreamUncompressed) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| framer.set_enable_compression(false); |
| { |
| @@ -980,24 +1383,43 @@ |
| headers["bar"] = "foo"; |
| headers["foo"] = "bar"; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x01, |
| + const unsigned char kPri = |
| + (SPDY_VERSION_FOR_TESTS != 2) ? 0xE0 : 0xC0; |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x20, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x00, |
| - 0xC0, 0x00, 0x00, 0x02, |
| + kPri, 0x00, 0x00, 0x02, |
| 0x00, 0x03, 'b', 'a', |
| 'r', 0x00, 0x03, 'f', |
| 'o', 'o', 0x00, 0x03, |
| 'f', 'o', 'o', 0x00, |
| 0x03, 'b', 'a', 'r' |
| }; |
| - scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( |
| - 1, 0, SPDY_PRIORITY_LOWEST, CONTROL_FLAG_NONE, |
| - false, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| - EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId( |
| - reinterpret_cast<const SpdyControlFrame*>(frame.get()))); |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x2a, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x00, |
| + kPri, 0x00, 0x00, 0x00, |
| + 0x00, 0x02, 0x00, 0x00, |
| + 0x00, 0x03, 'b', 'a', |
| + 'r', 0x00, 0x00, 0x00, |
| + 0x03, 'f', 'o', 'o', |
| + 0x00, 0x00, 0x00, 0x03, |
| + 'f', 'o', 'o', 0x00, |
| + 0x00, 0x00, 0x03, 'b', |
| + 'a', 'r' |
| + }; |
| + scoped_ptr<SpdySynStreamControlFrame> frame(framer.CreateSynStream( |
| + 1, 0, framer.GetLowestPriority(), CONTROL_FLAG_NONE, false, &headers)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| + EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get())); |
| } |
| { |
| @@ -1009,8 +1431,8 @@ |
| headers[""] = "foo"; |
| headers["foo"] = "bar"; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x01, |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x01, |
| 0x01, 0x00, 0x00, 0x1D, |
| 0x7f, 0xff, 0xff, 0xff, |
| 0x7f, 0xff, 0xff, 0xff, |
| @@ -1021,58 +1443,97 @@ |
| 0x00, 0x03, 'b', 'a', |
| 'r' |
| }; |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x01, |
| + 0x01, 0x00, 0x00, 0x27, |
| + 0x7f, 0xff, 0xff, 0xff, |
| + 0x7f, 0xff, 0xff, 0xff, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x02, 0x00, 0x00, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x03, 'f', 'o', |
| + 'o', 0x00, 0x00, 0x00, |
| + 0x03, 'f', 'o', 'o', |
| + 0x00, 0x00, 0x00, 0x03, |
| + 'b', 'a', 'r' |
| + }; |
| scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( |
| - 0x7fffffff, 0x7fffffff, SPDY_PRIORITY_HIGHEST, CONTROL_FLAG_FIN, |
| + 0x7fffffff, 0x7fffffff, framer.GetHighestPriority(), CONTROL_FLAG_FIN, |
| false, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| } |
| { |
| const char kDescription[] = |
| - "SYN_STREAM frame with a 0-length header val, highest pri, FIN, " |
| + "SYN_STREAM frame with a 0-length header val, high pri, FIN, " |
| "max stream ID"; |
| SpdyHeaderBlock headers; |
| headers["bar"] = "foo"; |
| headers["foo"] = ""; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x01, |
| + const unsigned char kPri = |
| + (SPDY_VERSION_FOR_TESTS != 2) ? 0x20 : 0x40; |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x01, |
| 0x01, 0x00, 0x00, 0x1D, |
| 0x7f, 0xff, 0xff, 0xff, |
| 0x7f, 0xff, 0xff, 0xff, |
| - 0x00, 0x00, 0x00, 0x02, |
| + kPri, 0x00, 0x00, 0x02, |
| 0x00, 0x03, 'b', 'a', |
| 'r', 0x00, 0x03, 'f', |
| 'o', 'o', 0x00, 0x03, |
| 'f', 'o', 'o', 0x00, |
| 0x00 |
| }; |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x01, |
| + 0x01, 0x00, 0x00, 0x27, |
| + 0x7f, 0xff, 0xff, 0xff, |
| + 0x7f, 0xff, 0xff, 0xff, |
| + kPri, 0x00, 0x00, 0x00, |
| + 0x00, 0x02, 0x00, 0x00, |
| + 0x00, 0x03, 'b', 'a', |
| + 'r', 0x00, 0x00, 0x00, |
| + 0x03, 'f', 'o', 'o', |
| + 0x00, 0x00, 0x00, 0x03, |
| + 'f', 'o', 'o', 0x00, |
| + 0x00, 0x00, 0x00 |
| + }; |
| scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( |
| - 0x7fffffff, 0x7fffffff, SPDY_PRIORITY_HIGHEST, CONTROL_FLAG_FIN, |
| - false, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + 0x7fffffff, 0x7fffffff, 1, CONTROL_FLAG_FIN, false, &headers)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| } |
| } |
| TEST_F(SpdyFramerTest, CreateSynStreamCompressed) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| framer.set_enable_compression(true); |
| { |
| const char kDescription[] = |
| - "SYN_STREAM frame, lowest pri, no FIN"; |
| + "SYN_STREAM frame, low pri, no FIN"; |
| SpdyHeaderBlock headers; |
| headers["bar"] = "foo"; |
| headers["foo"] = "bar"; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x01, |
| + const SpdyPriority priority = |
| + (SPDY_VERSION_FOR_TESTS != 2) ? 4 : 2; |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x25, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x00, |
| - 0xC0, 0x00, 0x38, 0xea, |
| + 0x80, 0x00, 0x38, 0xea, |
| 0xdf, 0xa2, 0x51, 0xb2, |
| 0x62, 0x60, 0x62, 0x60, |
| 0x4e, 0x4a, 0x2c, 0x62, |
| @@ -1081,15 +1542,32 @@ |
| 0x00, 0x00, 0x00, 0xff, |
| 0xff |
| }; |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x27, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x80, 0x00, 0x38, 0xEA, |
| + 0xE3, 0xC6, 0xA7, 0xC2, |
| + 0x02, 0xE5, 0x0E, 0x50, |
| + 0xC2, 0x4B, 0x4A, 0x04, |
| + 0xE5, 0x0B, 0xE6, 0xB4, |
| + 0xFC, 0x7C, 0x24, 0x0A, |
| + 0x28, 0x08, 0x00, 0x00, |
| + 0x00, 0xFF, 0xFF |
| + }; |
| scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( |
| - 1, 0, SPDY_PRIORITY_LOWEST, CONTROL_FLAG_NONE, |
| - true, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + 1, 0, priority, CONTROL_FLAG_NONE, true, &headers)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| } |
| } |
| TEST_F(SpdyFramerTest, CreateSynReplyUncompressed) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| framer.set_enable_compression(false); |
| { |
| @@ -1099,8 +1577,8 @@ |
| headers["bar"] = "foo"; |
| headers["foo"] = "bar"; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x02, |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x02, |
| 0x00, 0x00, 0x00, 0x1C, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x02, |
| @@ -1110,9 +1588,26 @@ |
| 'f', 'o', 'o', 0x00, |
| 0x03, 'b', 'a', 'r' |
| }; |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x02, |
| + 0x00, 0x00, 0x00, 0x24, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x02, |
| + 0x00, 0x00, 0x00, 0x03, |
| + 'b', 'a', 'r', 0x00, |
| + 0x00, 0x00, 0x03, 'f', |
| + 'o', 'o', 0x00, 0x00, |
| + 0x00, 0x03, 'f', 'o', |
| + 'o', 0x00, 0x00, 0x00, |
| + 0x03, 'b', 'a', 'r' |
| + }; |
| scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( |
| 1, CONTROL_FLAG_NONE, false, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| } |
| { |
| @@ -1123,8 +1618,8 @@ |
| headers[""] = "foo"; |
| headers["foo"] = "bar"; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x02, |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x02, |
| 0x01, 0x00, 0x00, 0x19, |
| 0x7f, 0xff, 0xff, 0xff, |
| 0x00, 0x00, 0x00, 0x02, |
| @@ -1134,9 +1629,26 @@ |
| 0x00, 0x03, 'b', 'a', |
| 'r' |
| }; |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x02, |
| + 0x01, 0x00, 0x00, 0x21, |
| + 0x7f, 0xff, 0xff, 0xff, |
| + 0x00, 0x00, 0x00, 0x02, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x00, 0x00, 0x03, |
| + 'f', 'o', 'o', 0x00, |
| + 0x00, 0x00, 0x03, 'f', |
| + 'o', 'o', 0x00, 0x00, |
| + 0x00, 0x03, 'b', 'a', |
| + 'r' |
| + }; |
| scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( |
| 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| } |
| { |
| @@ -1147,8 +1659,8 @@ |
| headers["bar"] = "foo"; |
| headers["foo"] = ""; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x02, |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x02, |
| 0x01, 0x00, 0x00, 0x19, |
| 0x7f, 0xff, 0xff, 0xff, |
| 0x00, 0x00, 0x00, 0x02, |
| @@ -1158,14 +1670,31 @@ |
| 'f', 'o', 'o', 0x00, |
| 0x00 |
| }; |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x02, |
| + 0x01, 0x00, 0x00, 0x21, |
| + 0x7f, 0xff, 0xff, 0xff, |
| + 0x00, 0x00, 0x00, 0x02, |
| + 0x00, 0x00, 0x00, 0x03, |
| + 'b', 'a', 'r', 0x00, |
| + 0x00, 0x00, 0x03, 'f', |
| + 'o', 'o', 0x00, 0x00, |
| + 0x00, 0x03, 'f', 'o', |
| + 'o', 0x00, 0x00, 0x00, |
| + 0x00 |
| + }; |
| scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( |
| 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| } |
| } |
| TEST_F(SpdyFramerTest, CreateSynReplyCompressed) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| framer.set_enable_compression(true); |
| { |
| @@ -1175,8 +1704,8 @@ |
| headers["bar"] = "foo"; |
| headers["foo"] = "bar"; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x02, |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x02, |
| 0x00, 0x00, 0x00, 0x21, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x38, 0xea, |
| @@ -1188,33 +1717,50 @@ |
| 0x00, 0x00, 0x00, 0xff, |
| 0xff |
| }; |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x02, |
| + 0x00, 0x00, 0x00, 0x21, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x38, 0xea, 0xe3, 0xc6, |
| + 0xa7, 0xc2, 0x02, 0xe5, |
| + 0x0e, 0x50, 0xc2, 0x4b, |
| + 0x4a, 0x04, 0xe5, 0x0b, |
| + 0xe6, 0xb4, 0xfc, 0x7c, |
| + 0x24, 0x0a, 0x28, 0x08, |
| + 0x00, 0x00, 0x00, 0xff, |
| + 0xff |
| + }; |
| scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( |
| 1, CONTROL_FLAG_NONE, true, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| } |
| } |
| TEST_F(SpdyFramerTest, CreateRstStream) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| { |
| const char kDescription[] = "RST_STREAM frame"; |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x03, |
| + 0x80, kVer, 0x00, 0x03, |
| 0x00, 0x00, 0x00, 0x08, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x01, |
| }; |
| - scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(1, PROTOCOL_ERROR)); |
| + scoped_ptr<SpdyRstStreamControlFrame> frame( |
| + framer.CreateRstStream(1, PROTOCOL_ERROR)); |
| CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| - EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId( |
| - reinterpret_cast<const SpdyControlFrame*>(frame.get()))); |
| + EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get())); |
| } |
| { |
| const char kDescription[] = "RST_STREAM frame with max stream ID"; |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x03, |
| + 0x80, kVer, 0x00, 0x03, |
| 0x00, 0x00, 0x00, 0x08, |
| 0x7f, 0xff, 0xff, 0xff, |
| 0x00, 0x00, 0x00, 0x01, |
| @@ -1227,7 +1773,7 @@ |
| { |
| const char kDescription[] = "RST_STREAM frame with max status code"; |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x03, |
| + 0x80, kVer, 0x00, 0x03, |
| 0x00, 0x00, 0x00, 0x08, |
| 0x7f, 0xff, 0xff, 0xff, |
| 0x00, 0x00, 0x00, 0x06, |
| @@ -1239,50 +1785,107 @@ |
| } |
| TEST_F(SpdyFramerTest, CreateSettings) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| { |
| + const char kDescription[] = "Network byte order SETTINGS frame"; |
| + |
| + uint32 kValue = 0x0a0b0c0d; |
| + uint8 kFlags = 0x04; |
| + uint32 kId = 0x030201; |
| + SettingsFlagsAndId idAndFlags(kFlags, kId); |
| + |
| + SpdySettings settings; |
| + settings.push_back(SpdySetting(idAndFlags, kValue)); |
| + |
| + EXPECT_EQ(kValue, settings.back().second); |
| + EXPECT_EQ(kFlags, settings.back().first.flags()); |
| + EXPECT_EQ(kId, settings.back().first.id()); |
| + |
| + const unsigned char kFrameDatav2[] = { |
| + 0x80, kVer, 0x00, 0x04, |
| + 0x00, 0x00, 0x00, 0x0c, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x01, 0x02, 0x03, 0x04, |
| + 0x0a, 0x0b, 0x0c, 0x0d, |
| + }; |
| + |
| + const unsigned char kFrameDatav3[] = { |
| + 0x80, kVer, 0x00, 0x04, |
| + 0x00, 0x00, 0x00, 0x0c, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x04, 0x03, 0x02, 0x01, |
| + 0x0a, 0x0b, 0x0c, 0x0d, |
| + }; |
| + |
| + scoped_ptr<SpdySettingsControlFrame> frame(framer.CreateSettings(settings)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kFrameDatav2 : kFrameDatav3, |
| + arraysize(kFrameDatav3)); // Size is unchanged among versions. |
| + EXPECT_EQ(SpdyFramer::kInvalidStream, |
| + SpdyFramer::GetControlFrameStreamId(frame.get())); |
| + |
| + // Make sure that ParseSettings also works as advertised. |
| + SpdySettings parsed_settings; |
| + EXPECT_TRUE(framer.ParseSettings(frame.get(), &parsed_settings)); |
| + EXPECT_EQ(settings.size(), parsed_settings.size()); |
| + EXPECT_EQ(kFlags, parsed_settings.back().first.flags()); |
| + EXPECT_EQ(kId, parsed_settings.back().first.id()); |
| + } |
| + |
| + { |
| const char kDescription[] = "Basic SETTINGS frame"; |
| SpdySettings settings; |
| - settings.push_back(SpdySetting(0x00000000, 0x00000000)); |
| - settings.push_back(SpdySetting(0xffffffff, 0x00000001)); |
| - settings.push_back(SpdySetting(0xff000001, 0x00000002)); |
| + settings.push_back( |
| + SpdySettingFromWireFormat(0x00000000, 0x00000000)); // 1st Setting |
| + settings.push_back( |
| + SpdySettingFromWireFormat(0xffffffff, 0x00000001)); // 2nd Setting |
| + settings.push_back( |
| + SpdySettingFromWireFormat(0xff000001, 0x00000002)); // 3rd Setting |
| // Duplicates allowed |
| - settings.push_back(SpdySetting(0x01000002, 0x00000003)); |
| - settings.push_back(SpdySetting(0x01000002, 0x00000003)); |
| + settings.push_back( |
| + SpdySettingFromWireFormat(0x01000002, 0x00000003)); // 4th Setting |
| + settings.push_back( |
| + SpdySettingFromWireFormat(0x01000002, 0x00000003)); // 5th Setting |
| - settings.push_back(SpdySetting(0x01000003, 0x000000ff)); |
| - settings.push_back(SpdySetting(0x01000004, 0xff000001)); |
| - settings.push_back(SpdySetting(0x01000004, 0xffffffff)); |
| + settings.push_back( |
| + SpdySettingFromWireFormat(0x01000003, 0x000000ff)); // 6th Setting |
| + settings.push_back( |
| + SpdySettingFromWireFormat(0x01000004, 0xff000001)); // 7th Setting |
| + settings.push_back( |
| + SpdySettingFromWireFormat(0x01000004, 0xffffffff)); // 8th Setting |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x04, |
| + 0x80, kVer, 0x00, 0x04, |
| 0x00, 0x00, 0x00, 0x44, |
| 0x00, 0x00, 0x00, 0x08, |
| + 0x00, 0x00, 0x00, 0x00, // 1st Setting |
| 0x00, 0x00, 0x00, 0x00, |
| - 0x00, 0x00, 0x00, 0x00, |
| - 0xff, 0xff, 0xff, 0xff, |
| + 0xff, 0xff, 0xff, 0xff, // 2nd Setting |
| 0x00, 0x00, 0x00, 0x01, |
| - 0xff, 0x00, 0x00, 0x01, |
| + 0x01, 0x00, 0x00, 0xff, // 3rd Setting |
| 0x00, 0x00, 0x00, 0x02, |
| - 0x01, 0x00, 0x00, 0x02, |
| + 0x02, 0x00, 0x00, 0x01, // 4th Setting |
| 0x00, 0x00, 0x00, 0x03, |
| - 0x01, 0x00, 0x00, 0x02, |
| + 0x02, 0x00, 0x00, 0x01, // 5th Setting |
| 0x00, 0x00, 0x00, 0x03, |
| - 0x01, 0x00, 0x00, 0x03, |
| + 0x03, 0x00, 0x00, 0x01, // 6th Setting |
| 0x00, 0x00, 0x00, 0xff, |
| - 0x01, 0x00, 0x00, 0x04, |
| + 0x04, 0x00, 0x00, 0x01, // 7th Setting |
| 0xff, 0x00, 0x00, 0x01, |
| - 0x01, 0x00, 0x00, 0x04, |
| + 0x04, 0x00, 0x00, 0x01, // 8th Setting |
| 0xff, 0xff, 0xff, 0xff, |
| }; |
| - scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + scoped_ptr<SpdySettingsControlFrame> frame(framer.CreateSettings(settings)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + kFrameData, |
| + arraysize(kFrameData)); |
| EXPECT_EQ(SpdyFramer::kInvalidStream, |
| - SpdyFramer::GetControlFrameStreamId( |
| - reinterpret_cast<const SpdyControlFrame*>(frame.get()))); |
| + SpdyFramer::GetControlFrameStreamId(frame.get())); |
| } |
| { |
| @@ -1291,7 +1894,7 @@ |
| SpdySettings settings; |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x04, |
| + 0x80, kVer, 0x00, 0x04, |
| 0x00, 0x00, 0x00, 0x04, |
| 0x00, 0x00, 0x00, 0x00, |
| }; |
| @@ -1300,62 +1903,43 @@ |
| } |
| } |
| -TEST_F(SpdyFramerTest, CreateNopFrame) { |
| - SpdyFramer framer; |
| - |
| - { |
| - const char kDescription[] = "NOOP frame"; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x05, |
| - 0x00, 0x00, 0x00, 0x00, |
| - }; |
| - scoped_ptr<SpdyFrame> frame(framer.CreateNopFrame()); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| - EXPECT_EQ(SpdyFramer::kInvalidStream, |
| - SpdyFramer::GetControlFrameStreamId( |
| - reinterpret_cast<const SpdyControlFrame*>(frame.get()))); |
| - } |
| -} |
| - |
| TEST_F(SpdyFramerTest, CreatePingFrame) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| { |
| const char kDescription[] = "PING frame"; |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x06, |
| + 0x80, kVer, 0x00, 0x06, |
| 0x00, 0x00, 0x00, 0x04, |
| 0x12, 0x34, 0x56, 0x78, |
| }; |
| - scoped_ptr<SpdyFrame> frame(framer.CreatePingFrame(0x12345678u)); |
| + scoped_ptr<SpdyPingControlFrame> frame(framer.CreatePingFrame(0x12345678u)); |
| CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| EXPECT_EQ(SpdyFramer::kInvalidStream, |
| - SpdyFramer::GetControlFrameStreamId( |
| - reinterpret_cast<const SpdyControlFrame*>(frame.get()))); |
| + SpdyFramer::GetControlFrameStreamId(frame.get())); |
| } |
| } |
| TEST_F(SpdyFramerTest, CreateGoAway) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| { |
| const char kDescription[] = "GOAWAY frame"; |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x07, |
| + 0x80, kVer, 0x00, 0x07, |
| 0x00, 0x00, 0x00, 0x04, |
| 0x00, 0x00, 0x00, 0x00, |
| }; |
| - scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0)); |
| + scoped_ptr<SpdyGoAwayControlFrame> frame(framer.CreateGoAway(0)); |
| CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| EXPECT_EQ(SpdyFramer::kInvalidStream, |
| - SpdyFramer::GetControlFrameStreamId( |
| - reinterpret_cast<const SpdyControlFrame*>(frame.get()))); |
| + SpdyFramer::GetControlFrameStreamId(frame.get())); |
| } |
| { |
| const char kDescription[] = "GOAWAY frame with max stream ID"; |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x07, |
| + 0x80, kVer, 0x00, 0x07, |
| 0x00, 0x00, 0x00, 0x04, |
| 0x7f, 0xff, 0xff, 0xff, |
| }; |
| @@ -1365,7 +1949,7 @@ |
| } |
| TEST_F(SpdyFramerTest, CreateHeadersUncompressed) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| framer.set_enable_compression(false); |
| { |
| @@ -1375,8 +1959,8 @@ |
| headers["bar"] = "foo"; |
| headers["foo"] = "bar"; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x08, |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x08, |
| 0x00, 0x00, 0x00, 0x1C, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x02, |
| @@ -1386,9 +1970,26 @@ |
| 'f', 'o', 'o', 0x00, |
| 0x03, 'b', 'a', 'r' |
| }; |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x08, |
| + 0x00, 0x00, 0x00, 0x24, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x00, 0x00, 0x00, 0x02, |
| + 0x00, 0x00, 0x00, 0x03, |
| + 'b', 'a', 'r', 0x00, |
| + 0x00, 0x00, 0x03, 'f', |
| + 'o', 'o', 0x00, 0x00, |
| + 0x00, 0x03, 'f', 'o', |
| + 'o', 0x00, 0x00, 0x00, |
| + 0x03, 'b', 'a', 'r' |
| + }; |
| scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( |
| 1, CONTROL_FLAG_NONE, false, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| } |
| { |
| @@ -1399,8 +2000,8 @@ |
| headers[""] = "foo"; |
| headers["foo"] = "bar"; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x08, |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x08, |
| 0x01, 0x00, 0x00, 0x19, |
| 0x7f, 0xff, 0xff, 0xff, |
| 0x00, 0x00, 0x00, 0x02, |
| @@ -1410,9 +2011,26 @@ |
| 0x00, 0x03, 'b', 'a', |
| 'r' |
| }; |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x08, |
| + 0x01, 0x00, 0x00, 0x21, |
| + 0x7f, 0xff, 0xff, 0xff, |
| + 0x00, 0x00, 0x00, 0x02, |
| + 0x00, 0x00, 0x00, 0x00, |
| + 0x00, 0x00, 0x00, 0x03, |
| + 'f', 'o', 'o', 0x00, |
| + 0x00, 0x00, 0x03, 'f', |
| + 'o', 'o', 0x00, 0x00, |
| + 0x00, 0x03, 'b', 'a', |
| + 'r' |
| + }; |
| scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( |
| 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| } |
| { |
| @@ -1423,8 +2041,8 @@ |
| headers["bar"] = "foo"; |
| headers["foo"] = ""; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x08, |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x08, |
| 0x01, 0x00, 0x00, 0x19, |
| 0x7f, 0xff, 0xff, 0xff, |
| 0x00, 0x00, 0x00, 0x02, |
| @@ -1434,14 +2052,31 @@ |
| 'f', 'o', 'o', 0x00, |
| 0x00 |
| }; |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x08, |
| + 0x01, 0x00, 0x00, 0x21, |
| + 0x7f, 0xff, 0xff, 0xff, |
| + 0x00, 0x00, 0x00, 0x02, |
| + 0x00, 0x00, 0x00, 0x03, |
| + 'b', 'a', 'r', 0x00, |
| + 0x00, 0x00, 0x03, 'f', |
| + 'o', 'o', 0x00, 0x00, |
| + 0x00, 0x03, 'f', 'o', |
| + 'o', 0x00, 0x00, 0x00, |
| + 0x00 |
| + }; |
| scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( |
| 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| } |
| } |
| TEST_F(SpdyFramerTest, CreateHeadersCompressed) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| framer.set_enable_compression(true); |
| { |
| @@ -1451,8 +2086,8 @@ |
| headers["bar"] = "foo"; |
| headers["foo"] = "bar"; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x08, |
| + const unsigned char kV2FrameData[] = { |
| + 0x80, kVer, 0x00, 0x08, |
| 0x00, 0x00, 0x00, 0x21, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x38, 0xea, |
| @@ -1464,33 +2099,50 @@ |
| 0x00, 0x00, 0x00, 0xff, |
| 0xff |
| }; |
| + const unsigned char kV3FrameData[] = { |
| + 0x80, kVer, 0x00, 0x08, |
| + 0x00, 0x00, 0x00, 0x21, |
| + 0x00, 0x00, 0x00, 0x01, |
| + 0x38, 0xea, 0xe3, 0xc6, |
| + 0xa7, 0xc2, 0x02, 0xe5, |
| + 0x0e, 0x50, 0xc2, 0x4b, |
| + 0x4a, 0x04, 0xe5, 0x0b, |
| + 0xe6, 0xb4, 0xfc, 0x7c, |
| + 0x24, 0x0a, 0x28, 0x08, |
| + 0x00, 0x00, 0x00, 0xff, |
| + 0xff |
| + }; |
| scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( |
| 1, CONTROL_FLAG_NONE, true, &headers)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| + CompareFrame(kDescription, |
| + *frame, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
| + (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
| + : arraysize(kV3FrameData)); |
| } |
| } |
| TEST_F(SpdyFramerTest, CreateWindowUpdate) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| { |
| const char kDescription[] = "WINDOW_UPDATE frame"; |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x09, |
| + 0x80, kVer, 0x00, 0x09, |
| 0x00, 0x00, 0x00, 0x08, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x01, |
| }; |
| - scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 1)); |
| + scoped_ptr<SpdyWindowUpdateControlFrame> frame( |
| + framer.CreateWindowUpdate(1, 1)); |
| CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| - EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId( |
| - reinterpret_cast<const SpdyControlFrame*>(frame.get()))); |
| + EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get())); |
| } |
| { |
| const char kDescription[] = "WINDOW_UPDATE frame with max stream ID"; |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x09, |
| + 0x80, kVer, 0x00, 0x09, |
| 0x00, 0x00, 0x00, 0x08, |
| 0x7f, 0xff, 0xff, 0xff, |
| 0x00, 0x00, 0x00, 0x01, |
| @@ -1502,7 +2154,7 @@ |
| { |
| const char kDescription[] = "WINDOW_UPDATE frame with max window delta"; |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x09, |
| + 0x80, kVer, 0x00, 0x09, |
| 0x00, 0x00, 0x00, 0x08, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x7f, 0xff, 0xff, 0xff, |
| @@ -1512,85 +2164,13 @@ |
| } |
| } |
| -TEST_F(SpdyFramerTest, CreateCredential) { |
| - SpdyFramer framer; |
| - |
| - { |
| - const char kDescription[] = "CREDENTIAL frame"; |
| - const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x0A, |
| - 0x00, 0x00, 0x00, 0x33, |
| - 0x00, 0x03, 0x00, 0x00, |
| - 0x00, 0x05, 'p', 'r', |
| - 'o', 'o', 'f', 0x00, |
| - 0x00, 0x00, 0x06, 'a', |
| - ' ', 'c', 'e', 'r', |
| - 't', 0x00, 0x00, 0x00, |
| - 0x0C, 'a', 'n', 'o', |
| - 't', 'h', 'e', 'r', |
| - ' ', 'c', 'e', 'r', |
| - 't', 0x00, 0x00, 0x00, |
| - 0x0A, 'f', 'i', 'n', |
| - 'a', 'l', ' ', 'c', |
| - 'e', 'r', 't', |
| - }; |
| - SpdyCredential credential; |
| - credential.slot = 3; |
| - credential.proof = "proof"; |
| - credential.certs.push_back("a cert"); |
| - credential.certs.push_back("another cert"); |
| - credential.certs.push_back("final cert"); |
| - scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential)); |
| - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
| - } |
| -} |
| - |
| -TEST_F(SpdyFramerTest, ParseCredentialFrame) { |
| - SpdyFramer framer; |
| - |
| - { |
| - unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x0A, |
| - 0x00, 0x00, 0x00, 0x33, |
| - 0x00, 0x03, 0x00, 0x00, |
| - 0x00, 0x05, 'p', 'r', |
| - 'o', 'o', 'f', 0x00, |
| - 0x00, 0x00, 0x06, 'a', |
| - ' ', 'c', 'e', 'r', |
| - 't', 0x00, 0x00, 0x00, |
| - 0x0C, 'a', 'n', 'o', |
| - 't', 'h', 'e', 'r', |
| - ' ', 'c', 'e', 'r', |
| - 't', 0x00, 0x00, 0x00, |
| - 0x0A, 'f', 'i', 'n', |
| - 'a', 'l', ' ', 'c', |
| - 'e', 'r', 't', |
| - }; |
| - SpdyCredentialControlFrame frame(reinterpret_cast<char*>(kFrameData), |
| - false); |
| - SpdyCredential credential; |
| - EXPECT_TRUE(SpdyFramer::ParseCredentialData(frame.payload(), |
| - frame.length(), |
| - &credential)); |
| - EXPECT_EQ(3u, credential.slot); |
| - EXPECT_EQ("proof", credential.proof); |
| - EXPECT_EQ("a cert", credential.certs.front()); |
| - credential.certs.erase(credential.certs.begin()); |
| - EXPECT_EQ("another cert", credential.certs.front()); |
| - credential.certs.erase(credential.certs.begin()); |
| - EXPECT_EQ("final cert", credential.certs.front()); |
| - credential.certs.erase(credential.certs.begin()); |
| - EXPECT_TRUE(credential.certs.empty()); |
| - } |
| -} |
| - |
| TEST_F(SpdyFramerTest, DuplicateFrame) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| { |
| const char kDescription[] = "PING frame"; |
| const unsigned char kFrameData[] = { |
| - 0x80, 0x02, 0x00, 0x06, |
| + 0x80, kVer, 0x00, 0x06, |
| 0x00, 0x00, 0x00, 0x04, |
| 0x12, 0x34, 0x56, 0x78, |
| }; |
| @@ -1618,7 +2198,7 @@ |
| headers["bar"] = "foo"; |
| headers["foo"] = "baz"; |
| headers["grue"] = val2.c_str(); |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| scoped_ptr<SpdySynStreamControlFrame> template_frame( |
| framer.CreateSynStream(1, // stream_id |
| 0, // associated_stream_id |
| @@ -1635,6 +2215,150 @@ |
| } |
| } |
| +TEST_F(SpdyFramerTest, ControlFrameSizesAreValidated) { |
| + // Create a GoAway frame that has a few extra bytes at the end. |
| + // We create enough overhead to require the framer to expand its frame buffer. |
| + size_t overhead = SpdyFramer::kUncompressedControlFrameBufferInitialSize; |
| + SpdyFramer framer(kVer); |
| + scoped_ptr<SpdyGoAwayControlFrame> goaway(framer.CreateGoAway(1)); |
| + goaway->set_length(goaway->length() + overhead); |
| + std::string pad('A', overhead); |
| + TestSpdyVisitor visitor; |
| + |
| + // First attempt without validation on. |
| + visitor.framer_.set_validate_control_frame_sizes(false); |
| + visitor.SimulateInFramer( |
| + reinterpret_cast<unsigned char*>(goaway->data()), |
| + goaway->length() - overhead + SpdyControlFrame::kHeaderSize); |
| + visitor.SimulateInFramer( |
| + reinterpret_cast<const unsigned char*>(pad.c_str()), |
| + overhead); |
| + EXPECT_EQ(0, visitor.error_count_); // Not an error. |
| + EXPECT_EQ(1, visitor.goaway_count_); // The goaway was parsed. |
| + |
| + // Attempt with validation on. |
| + visitor.framer_.set_validate_control_frame_sizes(true); |
| + visitor.SimulateInFramer( |
| + reinterpret_cast<unsigned char*>(goaway->data()), |
| + goaway->length() - overhead + SpdyControlFrame::kHeaderSize); |
| + visitor.SimulateInFramer( |
| + reinterpret_cast<const unsigned char*>(pad.c_str()), |
| + overhead); |
| + EXPECT_EQ(1, visitor.error_count_); // This generated an error. |
| + EXPECT_EQ(1, visitor.goaway_count_); // Unchanged from before. |
| +} |
| + |
| +TEST_F(SpdyFramerTest, ReadZeroLenSettingsFrame) { |
| + SpdyFramer framer(kVer); |
| + SpdySettings settings; |
| + scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); |
| + control_frame->set_length(0); |
| + TestSpdyVisitor visitor; |
| + visitor.use_compression_ = false; |
| + visitor.SimulateInFramer( |
| + reinterpret_cast<unsigned char*>(control_frame->data()), |
| + control_frame.get()->length() + SpdyControlFrame::kHeaderSize); |
| + // Should generate an error, since zero-len settings frames are unsupported. |
| + EXPECT_EQ(1, visitor.error_count_); |
| +} |
| + |
| +// Tests handling of SETTINGS frames with invalid length. |
| +TEST_F(SpdyFramerTest, ReadBogusLenSettingsFrame) { |
| + SpdyFramer framer(kVer); |
| + SpdySettings settings; |
| + // Add a setting to pad the frame so that we don't get a buffer overflow when |
| + // calling SimulateInFramer() below. |
| + settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002)); |
| + scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); |
| + control_frame->set_length(5); |
| + TestSpdyVisitor visitor; |
| + visitor.use_compression_ = false; |
| + visitor.SimulateInFramer( |
| + reinterpret_cast<unsigned char*>(control_frame->data()), |
| + control_frame.get()->length() + SpdyControlFrame::kHeaderSize); |
| + // Should generate an error, since zero-len settings frames are unsupported. |
| + EXPECT_EQ(1, visitor.error_count_); |
| +} |
| + |
| +// Tests handling of SETTINGS frames larger than the frame buffer size. |
| +TEST_F(SpdyFramerTest, ReadLargeSettingsFrame) { |
| + SpdyFramer framer(kVer); |
| + SpdySettings settings; |
| + settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002)); |
| + settings.push_back(SpdySetting(SettingsFlagsAndId(0, 2), 0x00000003)); |
| + settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000004)); |
| + scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); |
| + EXPECT_LT(SpdyFramer::kUncompressedControlFrameBufferInitialSize, |
| + control_frame->length() + SpdyControlFrame::kHeaderSize); |
| + TestSpdyVisitor visitor; |
| + visitor.use_compression_ = false; |
| + |
| + // Read all at once. |
| + visitor.SimulateInFramer( |
| + reinterpret_cast<unsigned char*>(control_frame->data()), |
| + control_frame->length() + SpdyControlFrame::kHeaderSize); |
| + EXPECT_EQ(0, visitor.error_count_); |
| + EXPECT_EQ(settings.size(), static_cast<unsigned>(visitor.setting_count_)); |
| + EXPECT_EQ(1, visitor.settings_frame_count_); |
| + |
| + // Read data in small chunks. |
| + size_t framed_data = 0; |
| + size_t unframed_data = control_frame->length() + |
| + SpdyControlFrame::kHeaderSize; |
| + size_t kReadChunkSize = 5; // Read five bytes at a time. |
| + while (unframed_data > 0) { |
| + size_t to_read = std::min(kReadChunkSize, unframed_data); |
| + visitor.SimulateInFramer( |
| + reinterpret_cast<unsigned char*>(control_frame->data() + framed_data), |
| + to_read); |
| + unframed_data -= to_read; |
| + framed_data += to_read; |
| + } |
| + EXPECT_EQ(0, visitor.error_count_); |
| + EXPECT_EQ(settings.size() * 2, static_cast<unsigned>(visitor.setting_count_)); |
| + EXPECT_EQ(2, visitor.settings_frame_count_); |
| +} |
| + |
| +// Tests handling of SETTINGS frame with duplicate entries. |
| +TEST_F(SpdyFramerTest, ReadDuplicateSettings) { |
| + SpdyFramer framer(kVer); |
| + SpdySettings settings; |
| + settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002)); |
| + settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000003)); |
| + // This last setting should not be processed due to error above. |
| + settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000003)); |
| + scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); |
| + TestSpdyVisitor visitor; |
| + visitor.use_compression_ = false; |
| + |
| + visitor.SimulateInFramer( |
| + reinterpret_cast<unsigned char*>(control_frame->data()), |
| + control_frame->length() + SpdyControlFrame::kHeaderSize); |
| + EXPECT_EQ(1, visitor.error_count_); |
| + EXPECT_EQ(1, visitor.setting_count_); |
| + EXPECT_EQ(1, visitor.settings_frame_count_); |
| +} |
| + |
| +// Tests handling of SETTINGS frame with entries out of order. |
| +TEST_F(SpdyFramerTest, ReadOutOfOrderSettings) { |
| + SpdyFramer framer(kVer); |
| + SpdySettings settings; |
| + settings.push_back(SpdySetting(SettingsFlagsAndId(0, 2), 0x00000002)); |
| + settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000003)); |
| + // This last setting should not be processed due to error above. |
| + settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000003)); |
| + scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); |
| + TestSpdyVisitor visitor; |
| + visitor.use_compression_ = false; |
| + |
| + visitor.SimulateInFramer( |
| + reinterpret_cast<unsigned char*>(control_frame->data()), |
| + control_frame->length() + SpdyControlFrame::kHeaderSize); |
| + EXPECT_EQ(1, visitor.error_count_); |
| + EXPECT_EQ(1, visitor.setting_count_); |
| + EXPECT_EQ(1, visitor.settings_frame_count_); |
| +} |
| + |
| TEST_F(SpdyFramerTest, ReadCredentialFrame) { |
| SpdyCredential credential; |
| credential.slot = 3; |
| @@ -1642,7 +2366,7 @@ |
| credential.certs.push_back("a cert"); |
| credential.certs.push_back("another cert"); |
| credential.certs.push_back("final cert"); |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| scoped_ptr<SpdyFrame> control_frame( |
| framer.CreateCredentialFrame(credential)); |
| EXPECT_TRUE(control_frame.get() != NULL); |
| @@ -1669,7 +2393,7 @@ |
| credential.certs.push_back("a cert"); |
| credential.certs.push_back("another cert"); |
| credential.certs.push_back("final cert"); |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| scoped_ptr<SpdyFrame> control_frame( |
| framer.CreateCredentialFrame(credential)); |
| EXPECT_TRUE(control_frame.get() != NULL); |
| @@ -1691,7 +2415,7 @@ |
| credential.certs.push_back("a cert"); |
| credential.certs.push_back("another cert"); |
| credential.certs.push_back("final cert"); |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| scoped_ptr<SpdyFrame> control_frame( |
| framer.CreateCredentialFrame(credential)); |
| EXPECT_TRUE(control_frame.get() != NULL); |
| @@ -1707,7 +2431,7 @@ |
| } |
| TEST_F(SpdyFramerTest, ReadGarbage) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| unsigned char garbage_frame[256]; |
| memset(garbage_frame, ~0, sizeof(garbage_frame)); |
| TestSpdyVisitor visitor; |
| @@ -1717,7 +2441,7 @@ |
| } |
| TEST_F(SpdyFramerTest, ReadGarbageWithValidVersion) { |
| - SpdyFramer framer; |
| + SpdyFramer framer(kVer); |
| char garbage_frame[256]; |
| memset(garbage_frame, ~0, sizeof(garbage_frame)); |
| SpdyControlFrame control_frame(&garbage_frame[0], false); |
| @@ -1760,9 +2484,12 @@ |
| EXPECT_STREQ("SPDY_CREDENTIAL_FRAME_PAYLOAD", |
| SpdyFramer::StateToString( |
| SpdyFramer::SPDY_CREDENTIAL_FRAME_PAYLOAD)); |
| + EXPECT_STREQ("SPDY_SETTINGS_FRAME_PAYLOAD", |
| + SpdyFramer::StateToString( |
| + SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD)); |
| EXPECT_STREQ("UNKNOWN_STATE", |
| SpdyFramer::StateToString( |
| - SpdyFramer::SPDY_CREDENTIAL_FRAME_PAYLOAD + 1)); |
| + SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD + 1)); |
| } |
| TEST(SpdyFramer, ErrorCodeToStringTest) { |
| @@ -1830,8 +2557,8 @@ |
| SpdyFramer::ControlTypeToString(HEADERS)); |
| EXPECT_STREQ("WINDOW_UPDATE", |
| SpdyFramer::ControlTypeToString(WINDOW_UPDATE)); |
| - EXPECT_STREQ("SETTINGS", |
| - SpdyFramer::ControlTypeToString(SETTINGS)); |
| + EXPECT_STREQ("CREDENTIAL", |
| + SpdyFramer::ControlTypeToString(CREDENTIAL)); |
| EXPECT_STREQ("UNKNOWN_CONTROL_TYPE", |
| SpdyFramer::ControlTypeToString(NUM_CONTROL_FRAME_TYPES)); |
| } |
| @@ -1845,7 +2572,7 @@ |
| SpdyFramer::GetMinimumControlFrameSize(RST_STREAM)); |
| EXPECT_EQ(SpdySettingsControlFrame::size(), |
| SpdyFramer::GetMinimumControlFrameSize(SETTINGS)); |
| - EXPECT_EQ(SpdyNoOpControlFrame::size(), |
| + EXPECT_EQ(SpdyFrame::kHeaderSize, |
| SpdyFramer::GetMinimumControlFrameSize(NOOP)); |
| EXPECT_EQ(SpdyPingControlFrame::size(), |
| SpdyFramer::GetMinimumControlFrameSize(PING)); |
| @@ -1861,11 +2588,34 @@ |
| SpdyFramer::GetMinimumControlFrameSize(NUM_CONTROL_FRAME_TYPES)); |
| } |
| -std::string RandomString(int length) { |
| - std::string rv; |
| - for (int index = 0; index < length; index++) |
| - rv += static_cast<char>('a' + (rand() % 26)); |
| - return rv; |
| +TEST(SpdyFramer, CatchProbableHttpResponse) { |
| + SpdyFramerTestUtil::DecompressionVisitor visitor; |
| + visitor.set_allow_data_frames(true); |
| + { |
| + SpdyFramer framer(kVer); |
| + framer.set_visitor(&visitor); |
| + framer.ProcessInput("HTTP/1.1", 8); |
| + EXPECT_TRUE(framer.probable_http_response()); |
| + } |
| + { |
| + SpdyFramer framer(kVer); |
| + framer.set_visitor(&visitor); |
| + framer.ProcessInput("HTTP/1.0", 8); |
| + EXPECT_TRUE(framer.probable_http_response()); |
| + } |
| } |
| +TEST(SpdyFramer, SettingsFlagsAndId) { |
| + const uint32 kId = 0x020304; |
| + const uint32 kFlags = 0x01; |
| + const uint32 kWireFormat = |
| + htonl((SPDY_VERSION_FOR_TESTS < 3) ? 0x04030201 : 0x01020304); |
| + |
| + SettingsFlagsAndId id_and_flags = |
| + SettingsFlagsAndId::FromWireFormat(SPDY_VERSION_FOR_TESTS, kWireFormat); |
| + EXPECT_EQ(kId, id_and_flags.id()); |
| + EXPECT_EQ(kFlags, id_and_flags.flags()); |
| + EXPECT_EQ(kWireFormat, id_and_flags.GetWireFormat(SPDY_VERSION_FOR_TESTS)); |
| +} |
| + |
| } // namespace |