Index: net/spdy/spdy_framer_spdy2_test.cc |
=================================================================== |
--- net/spdy/spdy_framer_spdy2_test.cc (working copy) |
+++ net/spdy/spdy_framer_spdy2_test.cc (working copy) |
@@ -11,13 +11,152 @@ |
#include "net/spdy/spdy_frame_builder.h" |
#include "testing/platform_test.h" |
+namespace { |
+ |
+// Default SPDY version for unit tests. |
+const int SPDY_VERSION_FOR_TESTS = 2; |
+ |
+// 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; |
+ |
+spdy::SpdySetting SpdySettingFromWireFormat(uint32 key, uint32 value) { |
+ return spdy::SpdySetting( |
+ spdy::SettingsFlagsAndId::FromWireFormat(SPDY_VERSION_FOR_TESTS, key), |
+ value); |
+} |
+ |
+} // namespace |
+ |
namespace spdy { |
-namespace test { |
+namespace test_spdy2 { |
+static const size_t kMaxDecompressedSize = 1024; |
+ |
+class SpdyFramerTestUtil { |
+ public: |
+ // Decompress a single frame using the decompression context held by |
+ // the SpdyFramer. The implemention 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"; |
static const int kColumns = 4; |
const int kSizeLimit = 1024; |
@@ -58,8 +197,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 = std::min(actual_len, expected_len); |
+ const int max_len = std::max(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 +228,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 +308,9 @@ |
case CREDENTIAL: |
credential_count_++; |
break; |
+ case SETTINGS: |
+ settings_frame_count_++; |
+ break; |
default: |
DLOG(FATAL); // Error! |
} |
@@ -173,6 +318,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 +331,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 +346,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 +422,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. |
@@ -297,7 +449,7 @@ |
SpdyCredential credential_; |
}; |
-} // namespace test |
+} // namespace test_spdy2 |
} // namespace spdy |
@@ -315,12 +467,13 @@ |
using spdy::DATA_FLAG_COMPRESSED; |
using spdy::DATA_FLAG_FIN; |
using spdy::SYN_STREAM; |
-using spdy::test::CompareCharArraysWithHexError; |
-using spdy::test::TestSpdyVisitor; |
+using spdy::test_spdy2::CompareCharArraysWithHexError; |
+using spdy::test_spdy2::SpdyFramerTestUtil; |
+using spdy::test_spdy2::TestSpdyVisitor; |
namespace spdy { |
-TEST(SpdyFrameBuilderTest, WriteLimits) { |
+TEST(SpdyFrameBuilderSpdy2Test, WriteLimits) { |
SpdyFrameBuilder builder(kLengthMask + 4); |
// length field should fail. |
EXPECT_FALSE(builder.WriteBytes(reinterpret_cast<const void*>(0x1), |
@@ -335,7 +488,7 @@ |
EXPECT_EQ(4 + kLengthMask, static_cast<unsigned>(builder.length())); |
} |
-class SpdyFramerTest : public PlatformTest { |
+class SpdyFramerSpdy2Test : public PlatformTest { |
public: |
virtual void TearDown() {} |
@@ -382,11 +535,11 @@ |
// Test that we can encode and decode a SpdyHeaderBlock in serialized form. |
-TEST_F(SpdyFramerTest, HeaderBlockInBuffer) { |
+TEST_F(SpdyFramerSpdy2Test, HeaderBlockInBuffer) { |
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( |
@@ -405,11 +558,11 @@ |
} |
// Test that if there's not a full frame, we fail to parse it. |
-TEST_F(SpdyFramerTest, UndersizedHeaderBlockInBuffer) { |
+TEST_F(SpdyFramerSpdy2Test, UndersizedHeaderBlockInBuffer) { |
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( |
@@ -424,7 +577,7 @@ |
&new_headers)); |
} |
-TEST_F(SpdyFramerTest, OutOfOrderHeaders) { |
+TEST_F(SpdyFramerSpdy2Test, OutOfOrderHeaders) { |
// Frame builder with plentiful buffer size. |
SpdyFrameBuilder frame(1024); |
@@ -435,12 +588,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,14 +609,85 @@ |
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, DuplicateHeader) { |
+TEST_F(SpdyFramerSpdy2Test, 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(SpdyFramerSpdy2Test, 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(SpdyFramerSpdy2Test, DuplicateHeader) { |
// Frame builder with plentiful buffer size. |
SpdyFrameBuilder frame(1024); |
@@ -467,12 +698,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 +719,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(), |
@@ -489,7 +727,7 @@ |
&new_headers)); |
} |
-TEST_F(SpdyFramerTest, MultiValueHeader) { |
+TEST_F(SpdyFramerSpdy2Test, MultiValueHeader) { |
// Frame builder with plentiful buffer size. |
SpdyFrameBuilder frame(1024); |
@@ -500,11 +738,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 +756,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(), |
@@ -522,7 +765,7 @@ |
EXPECT_EQ(value, new_headers.find("name")->second); |
} |
-TEST_F(SpdyFramerTest, BasicCompression) { |
+TEST_F(SpdyFramerSpdy2Test, BasicCompression) { |
SpdyHeaderBlock headers; |
headers["server"] = "SpdyServer 1.0"; |
headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; |
@@ -531,7 +774,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 +787,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 +811,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 |
+TEST_F(SpdyFramerSpdy2Test, Basic) { |
+ 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 +821,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 +832,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 +844,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 +859,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_); |
@@ -656,9 +943,9 @@ |
} |
// 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 |
+TEST_F(SpdyFramerSpdy2Test, FinOnDataFrame) { |
+ 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 +953,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 +970,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_); |
@@ -699,9 +1020,9 @@ |
} |
// 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 |
+TEST_F(SpdyFramerSpdy2Test, FinOnSynReplyFrame) { |
+ 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 +1030,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 +1038,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_); |
@@ -732,9 +1078,9 @@ |
EXPECT_EQ(0, visitor.data_frame_count_); |
} |
-TEST_F(SpdyFramerTest, HeaderCompression) { |
- SpdyFramer send_framer; |
- SpdyFramer recv_framer; |
+TEST_F(SpdyFramerSpdy2Test, HeaderCompression) { |
+ SpdyFramer send_framer(kVer); |
+ SpdyFramer recv_framer(kVer); |
send_framer.set_enable_compression(true); |
recv_framer.set_enable_compression(true); |
@@ -751,33 +1097,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 +1131,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(); |
@@ -816,8 +1157,8 @@ |
} |
// Verify we don't leak when we leave streams unclosed |
-TEST_F(SpdyFramerTest, UnclosedStreamDataCompressors) { |
- SpdyFramer send_framer; |
+TEST_F(SpdyFramerSpdy2Test, UnclosedStreamDataCompressors) { |
+ SpdyFramer send_framer(kVer); |
send_framer.set_enable_compression(true); |
@@ -830,7 +1171,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 +1179,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 +1208,76 @@ |
EXPECT_EQ(0, send_framer.num_stream_decompressors()); |
} |
-TEST_F(SpdyFramerTest, WindowUpdateFrame) { |
+// Verify we can decompress the stream even if handed over to the |
+// framer 1 byte at a time. |
+TEST_F(SpdyFramerSpdy2Test, 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(SpdyFramerSpdy2Test, 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 |
@@ -883,8 +1288,8 @@ |
memcmp(window_update_frame->data(), expected_data_frame, 16)); |
} |
-TEST_F(SpdyFramerTest, CreateDataFrame) { |
- SpdyFramer framer; |
+TEST_F(SpdyFramerSpdy2Test, CreateDataFrame) { |
+ SpdyFramer framer(kVer); |
{ |
const char kDescription[] = "'hello' data frame, no FIN"; |
@@ -969,8 +1374,8 @@ |
} |
} |
-TEST_F(SpdyFramerTest, CreateSynStreamUncompressed) { |
- SpdyFramer framer; |
+TEST_F(SpdyFramerSpdy2Test, CreateSynStreamUncompressed) { |
+ SpdyFramer framer(kVer); |
framer.set_enable_compression(false); |
{ |
@@ -980,24 +1385,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 +1433,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 +1445,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; |
+TEST_F(SpdyFramerSpdy2Test, CreateSynStreamCompressed) { |
+ 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 +1544,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; |
+TEST_F(SpdyFramerSpdy2Test, CreateSynReplyUncompressed) { |
+ SpdyFramer framer(kVer); |
framer.set_enable_compression(false); |
{ |
@@ -1099,8 +1579,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 +1590,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 +1620,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 +1631,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 +1661,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 +1672,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; |
+TEST_F(SpdyFramerSpdy2Test, CreateSynReplyCompressed) { |
+ SpdyFramer framer(kVer); |
framer.set_enable_compression(true); |
{ |
@@ -1175,8 +1706,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 +1719,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; |
+TEST_F(SpdyFramerSpdy2Test, CreateRstStream) { |
+ 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 +1775,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, |
@@ -1238,51 +1786,108 @@ |
} |
} |
-TEST_F(SpdyFramerTest, CreateSettings) { |
- SpdyFramer framer; |
+TEST_F(SpdyFramerSpdy2Test, CreateSettings) { |
+ 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 +1896,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 +1905,43 @@ |
} |
} |
-TEST_F(SpdyFramerTest, CreateNopFrame) { |
- SpdyFramer framer; |
+TEST_F(SpdyFramerSpdy2Test, CreatePingFrame) { |
+ SpdyFramer framer(kVer); |
{ |
- 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; |
- |
- { |
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; |
+TEST_F(SpdyFramerSpdy2Test, CreateGoAway) { |
+ 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, |
}; |
@@ -1364,8 +1950,8 @@ |
} |
} |
-TEST_F(SpdyFramerTest, CreateHeadersUncompressed) { |
- SpdyFramer framer; |
+TEST_F(SpdyFramerSpdy2Test, CreateHeadersUncompressed) { |
+ SpdyFramer framer(kVer); |
framer.set_enable_compression(false); |
{ |
@@ -1375,8 +1961,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 +1972,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 +2002,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 +2013,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 +2043,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 +2054,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; |
+TEST_F(SpdyFramerSpdy2Test, CreateHeadersCompressed) { |
+ SpdyFramer framer(kVer); |
framer.set_enable_compression(true); |
{ |
@@ -1451,8 +2088,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 +2101,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; |
+TEST_F(SpdyFramerSpdy2Test, CreateWindowUpdate) { |
+ 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 +2156,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 +2166,13 @@ |
} |
} |
-TEST_F(SpdyFramerTest, CreateCredential) { |
- SpdyFramer framer; |
+TEST_F(SpdyFramerSpdy2Test, DuplicateFrame) { |
+ SpdyFramer framer(kVer); |
{ |
- 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; |
- |
- { |
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, |
}; |
@@ -1607,7 +2189,7 @@ |
// the framer to overrun the buffer, and smash other heap contents. This test |
// relies on the debug version of the heap manager, which checks for buffer |
// overrun errors during delete processing. Regression test for b/2974814. |
-TEST_F(SpdyFramerTest, ExpandBuffer_HeapSmash) { |
+TEST_F(SpdyFramerSpdy2Test, ExpandBuffer_HeapSmash) { |
// Sweep through the area of problematic values, to make sure we always cover |
// the danger zone, even if it moves around at bit due to SPDY changes. |
for (uint16 val2_len = SpdyFramer::kControlFrameBufferInitialSize - 50; |
@@ -1618,7 +2200,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,14 +2217,158 @@ |
} |
} |
-TEST_F(SpdyFramerTest, ReadCredentialFrame) { |
+TEST_F(SpdyFramerSpdy2Test, 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(SpdyFramerSpdy2Test, 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(SpdyFramerSpdy2Test, 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(SpdyFramerSpdy2Test, 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(SpdyFramerSpdy2Test, 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(SpdyFramerSpdy2Test, 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(SpdyFramerSpdy2Test, ReadCredentialFrame) { |
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"); |
- SpdyFramer framer; |
+ SpdyFramer framer(kVer); |
scoped_ptr<SpdyFrame> control_frame( |
framer.CreateCredentialFrame(credential)); |
EXPECT_TRUE(control_frame.get() != NULL); |
@@ -1662,14 +2388,14 @@ |
} |
} |
-TEST_F(SpdyFramerTest, ReadCredentialFrameWithCorruptProof) { |
+TEST_F(SpdyFramerSpdy2Test, ReadCredentialFrameWithCorruptProof) { |
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"); |
- SpdyFramer framer; |
+ SpdyFramer framer(kVer); |
scoped_ptr<SpdyFrame> control_frame( |
framer.CreateCredentialFrame(credential)); |
EXPECT_TRUE(control_frame.get() != NULL); |
@@ -1684,14 +2410,14 @@ |
EXPECT_EQ(1, visitor.error_count_); |
} |
-TEST_F(SpdyFramerTest, ReadCredentialFrameWithCorruptCertificate) { |
+TEST_F(SpdyFramerSpdy2Test, ReadCredentialFrameWithCorruptCertificate) { |
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"); |
- SpdyFramer framer; |
+ SpdyFramer framer(kVer); |
scoped_ptr<SpdyFrame> control_frame( |
framer.CreateCredentialFrame(credential)); |
EXPECT_TRUE(control_frame.get() != NULL); |
@@ -1706,8 +2432,8 @@ |
EXPECT_EQ(1, visitor.error_count_); |
} |
-TEST_F(SpdyFramerTest, ReadGarbage) { |
- SpdyFramer framer; |
+TEST_F(SpdyFramerSpdy2Test, ReadGarbage) { |
+ SpdyFramer framer(kVer); |
unsigned char garbage_frame[256]; |
memset(garbage_frame, ~0, sizeof(garbage_frame)); |
TestSpdyVisitor visitor; |
@@ -1716,12 +2442,12 @@ |
EXPECT_EQ(1, visitor.error_count_); |
} |
-TEST_F(SpdyFramerTest, ReadGarbageWithValidVersion) { |
- SpdyFramer framer; |
+TEST_F(SpdyFramerSpdy2Test, ReadGarbageWithValidVersion) { |
+ SpdyFramer framer(kVer); |
char garbage_frame[256]; |
memset(garbage_frame, ~0, sizeof(garbage_frame)); |
SpdyControlFrame control_frame(&garbage_frame[0], false); |
- control_frame.set_version(kSpdyProtocolVersion); |
+ control_frame.set_version(SPDY_VERSION_FOR_TESTS); |
TestSpdyVisitor visitor; |
visitor.use_compression_ = false; |
visitor.SimulateInFramer( |
@@ -1730,7 +2456,7 @@ |
EXPECT_EQ(1, visitor.error_count_); |
} |
-TEST(SpdyFramer, StateToStringTest) { |
+TEST_F(SpdyFramerSpdy2Test, StateToStringTest) { |
EXPECT_STREQ("ERROR", |
SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR)); |
EXPECT_STREQ("DONE", |
@@ -1760,12 +2486,15 @@ |
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) { |
+TEST_F(SpdyFramerSpdy2Test, ErrorCodeToStringTest) { |
EXPECT_STREQ("NO_ERROR", |
SpdyFramer::ErrorCodeToString(SpdyFramer::SPDY_NO_ERROR)); |
EXPECT_STREQ("INVALID_CONTROL_FRAME", |
@@ -1790,7 +2519,7 @@ |
SpdyFramer::ErrorCodeToString(SpdyFramer::LAST_ERROR)); |
} |
-TEST(SpdyFramer, StatusCodeToStringTest) { |
+TEST_F(SpdyFramerSpdy2Test, StatusCodeToStringTest) { |
EXPECT_STREQ("INVALID", |
SpdyFramer::StatusCodeToString(INVALID)); |
EXPECT_STREQ("PROTOCOL_ERROR", |
@@ -1811,7 +2540,7 @@ |
SpdyFramer::StatusCodeToString(NUM_STATUS_CODES)); |
} |
-TEST(SpdyFramer, ControlTypeToStringTest) { |
+TEST_F(SpdyFramerSpdy2Test, ControlTypeToStringTest) { |
EXPECT_STREQ("SYN_STREAM", |
SpdyFramer::ControlTypeToString(SYN_STREAM)); |
EXPECT_STREQ("SYN_REPLY", |
@@ -1830,13 +2559,13 @@ |
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)); |
} |
-TEST(SpdyFramer, GetMinimumControlFrameSizeTest) { |
+TEST_F(SpdyFramerSpdy2Test, GetMinimumControlFrameSizeTest) { |
EXPECT_EQ(SpdySynStreamControlFrame::size(), |
SpdyFramer::GetMinimumControlFrameSize(SYN_STREAM)); |
EXPECT_EQ(SpdySynReplyControlFrame::size(), |
@@ -1845,7 +2574,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 +2590,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_F(SpdyFramerSpdy2Test, 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_F(SpdyFramerSpdy2Test, 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 |