diff options
author | mlloyd@chromium.org <mlloyd@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-08 20:50:13 +0000 |
---|---|---|
committer | mlloyd@chromium.org <mlloyd@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-08 20:50:13 +0000 |
commit | e9eeaf55115c9ac8bb991d318b4427beee69e735 (patch) | |
tree | c491c5506ecb583ca9cdae84c7e92fbde2287707 /net | |
parent | a13e022a717bd7d9e43681aafd4201573bcd3147 (diff) | |
download | chromium_src-e9eeaf55115c9ac8bb991d318b4427beee69e735.zip chromium_src-e9eeaf55115c9ac8bb991d318b4427beee69e735.tar.gz chromium_src-e9eeaf55115c9ac8bb991d318b4427beee69e735.tar.bz2 |
Adds tests for the SpdyFramer.Create* frame creation methods.
Also tightens up and fixes some of the DCHECKs in the frame
creation logic to address issues discovered while writing
the tests.
BUG=None
TEST=net_unittests pass
Review URL: http://codereview.chromium.org/2834046
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@51888 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/spdy/spdy_bitmasks.h | 6 | ||||
-rw-r--r-- | net/spdy/spdy_framer.cc | 51 | ||||
-rw-r--r-- | net/spdy/spdy_framer.h | 4 | ||||
-rw-r--r-- | net/spdy/spdy_framer_test.cc | 517 | ||||
-rw-r--r-- | net/spdy/spdy_protocol.h | 11 | ||||
-rw-r--r-- | net/spdy/spdy_protocol_test.cc | 9 |
6 files changed, 576 insertions, 22 deletions
diff --git a/net/spdy/spdy_bitmasks.h b/net/spdy/spdy_bitmasks.h index 40403e1..03752e3 100644 --- a/net/spdy/spdy_bitmasks.h +++ b/net/spdy/spdy_bitmasks.h @@ -22,6 +22,12 @@ const unsigned int kLengthMask = 0xffffff; // Mask the Id from a SETTINGS id. const unsigned int kSettingsIdMask = 0xffffff; +// Legal flags on data packets. +const int kDataFlagsMask = 0x03; + +// Legal flags on control packets. +const int kControlFlagsMask = 0x03; + } // namespace spdy #endif // NET_SPDY_SPDY_BITMASKS_H_ diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc index cd573a5..bb5d0fe 100644 --- a/net/spdy/spdy_framer.cc +++ b/net/spdy/spdy_framer.cc @@ -111,7 +111,7 @@ size_t SpdyFramer::BytesSafeToRead() const { case SPDY_RESET: return 0; case SPDY_READING_COMMON_HEADER: - DCHECK(current_frame_len_ < SpdyFrame::size()); + DCHECK_LT(current_frame_len_, SpdyFrame::size()); return SpdyFrame::size() - current_frame_len_; case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER: return 0; @@ -208,7 +208,7 @@ size_t SpdyFramer::ProcessInput(const char* data, size_t len) { size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) { // This should only be called when we're in the SPDY_READING_COMMON_HEADER // state. - DCHECK(state_ == SPDY_READING_COMMON_HEADER); + DCHECK_EQ(state_, SPDY_READING_COMMON_HEADER); int original_len = len; SpdyFrame current_frame(current_frame_buffer_, false); @@ -422,7 +422,7 @@ size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) { } void SpdyFramer::ExpandControlFrameBuffer(size_t size) { - DCHECK(size < kControlFrameBufferMaxSize); + DCHECK_LT(size, kControlFrameBufferMaxSize); if (size < current_frame_capacity_) return; @@ -517,6 +517,10 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( SpdyControlFlags flags, bool compressed, SpdyHeaderBlock* headers) { SpdyFrameBuilder frame; + DCHECK_GT(stream_id, static_cast<SpdyStreamId>(0)); + DCHECK_EQ(0u, stream_id & ~kStreamIdMask); + DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask); + frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion); frame.WriteUInt16(SYN_STREAM); frame.WriteUInt32(0); // Placeholder for the length and flags @@ -527,15 +531,18 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( frame.WriteUInt16(headers->size()); // Number of headers. SpdyHeaderBlock::iterator it; for (it = headers->begin(); it != headers->end(); ++it) { - frame.WriteString(it->first); - frame.WriteString(it->second); + bool wrote_header; + wrote_header = frame.WriteString(it->first); + wrote_header &= frame.WriteString(it->second); + DCHECK(wrote_header); } // Write the length and flags. size_t length = frame.length() - SpdyFrame::size(); - DCHECK(length < static_cast<size_t>(kLengthMask)); + DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask)); FlagsAndLength flags_length; flags_length.length_ = htonl(static_cast<uint32>(length)); + DCHECK_EQ(0, flags & ~kControlFlagsMask); flags_length.flags_[0] = flags; frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length)); @@ -549,7 +556,12 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( /* static */ SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(SpdyStreamId stream_id, - int status) { + SpdyStatusCodes status) { + DCHECK_GT(stream_id, 0u); + DCHECK_EQ(0u, stream_id & ~kStreamIdMask); + DCHECK_NE(status, INVALID); + DCHECK_LT(status, NUM_STATUS_CODES); + SpdyFrameBuilder frame; frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion); frame.WriteUInt16(RST_STREAM); @@ -562,6 +574,8 @@ SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(SpdyStreamId stream_id, /* static */ SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway( SpdyStreamId last_accepted_stream_id) { + DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask); + SpdyFrameBuilder frame; frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion); frame.WriteUInt16(GOAWAY); @@ -575,6 +589,11 @@ SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway( SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate( SpdyStreamId stream_id, uint32 delta_window_size) { + DCHECK_GT(stream_id, 0u); + DCHECK_EQ(0u, stream_id & ~kStreamIdMask); + DCHECK_GT(delta_window_size, 0u); + DCHECK_LE(delta_window_size, 0x80000000u); // 2^31 + SpdyFrameBuilder frame; frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion); frame.WriteUInt16(WINDOW_UPDATE); @@ -607,6 +626,8 @@ SpdySettingsControlFrame* SpdyFramer::CreateSettings( SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id, SpdyControlFlags flags, bool compressed, SpdyHeaderBlock* headers) { + DCHECK_GT(stream_id, 0u); + DCHECK_EQ(0u, stream_id & ~kStreamIdMask); SpdyFrameBuilder frame; @@ -619,15 +640,18 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id, frame.WriteUInt16(headers->size()); // Number of headers. SpdyHeaderBlock::iterator it; for (it = headers->begin(); it != headers->end(); ++it) { - frame.WriteString(it->first); - frame.WriteString(it->second); + bool wrote_header; + wrote_header = frame.WriteString(it->first); + wrote_header &= frame.WriteString(it->second); + DCHECK(wrote_header); } // Write the length and flags. size_t length = frame.length() - SpdyFrame::size(); - DCHECK(length < static_cast<size_t>(kLengthMask)); + DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask)); FlagsAndLength flags_length; flags_length.length_ = htonl(static_cast<uint32>(length)); + DCHECK_EQ(0, flags & ~kControlFlagsMask); flags_length.flags_[0] = flags; frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length)); @@ -641,14 +665,17 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id, SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id, const char* data, - uint32 len, uint32 flags) { + uint32 len, SpdyDataFlags flags) { SpdyFrameBuilder frame; + DCHECK_GT(stream_id, 0u); + DCHECK_EQ(0u, stream_id & ~kStreamIdMask); frame.WriteUInt32(stream_id); - DCHECK(len < static_cast<size_t>(kLengthMask)); + DCHECK_EQ(0u, len & ~static_cast<size_t>(kLengthMask)); FlagsAndLength flags_length; flags_length.length_ = htonl(len); + DCHECK_EQ(0, flags & ~kDataFlagsMask); flags_length.flags_[0] = flags; frame.WriteBytes(&flags_length, sizeof(flags_length)); diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h index c905dec..a0ea64d 100644 --- a/net/spdy/spdy_framer.h +++ b/net/spdy/spdy_framer.h @@ -154,7 +154,7 @@ class SpdyFramer { SpdyHeaderBlock* headers); static SpdyRstStreamControlFrame* CreateRstStream(SpdyStreamId stream_id, - int status); + SpdyStatusCodes status); // Creates an instance of SpdyGoAwayControlFrame. The GOAWAY frame is used // prior to the shutting down of the TCP connection, and includes the @@ -197,7 +197,7 @@ class SpdyFramer { // To create a compressed frame, enable DATA_FLAG_COMPRESSED. // To mark this frame as the last data frame, enable DATA_FLAG_FIN. SpdyDataFrame* CreateDataFrame(SpdyStreamId stream_id, const char* data, - uint32 len, uint32 flags); + uint32 len, SpdyDataFlags flags); static SpdyControlFrame* CreateNopFrame(); diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc index afedbba..895e4e9 100644 --- a/net/spdy/spdy_framer_test.cc +++ b/net/spdy/spdy_framer_test.cc @@ -15,6 +15,32 @@ namespace spdy { namespace test { +std::string HexDump(const unsigned char* data, int length) { + static const char kHexChars[] = "0123456789ABCDEF"; + static const int kColumns = 4; + + std::string hex; + for (const unsigned char* row = data; length > 0; + row += kColumns, length -= kColumns) { + for (const unsigned char *p = row; p < row + 4; ++p) { + if (p < row + length) { + hex += kHexChars[(*p & 0xf0) >> 4]; + hex += kHexChars[*p & 0x0f]; + hex += ' '; + } else { + hex += " "; + } + } + hex = hex + ' '; + + for (const unsigned char *p = row; p < row + 4 && p < row + length; ++p) + hex += (*p >= 0x20 && *p <= 0x7f) ? (*p) : '.'; + + hex = hex + '\n'; + } + return hex; +} + void FramerSetEnableCompressionHelper(SpdyFramer* framer, bool compress) { framer->set_enable_compression(compress); } @@ -126,6 +152,7 @@ using spdy::DATA_FLAG_COMPRESSED; using spdy::DATA_FLAG_FIN; using spdy::SYN_STREAM; using spdy::test::FramerSetEnableCompressionHelper; +using spdy::test::HexDump; using spdy::test::TestSpdyVisitor; namespace spdy { @@ -133,6 +160,25 @@ namespace spdy { class SpdyFramerTest : public PlatformTest { public: virtual void TearDown() {} + + protected: + void CompareFrame(const std::string& description, + const SpdyFrame& actual, + const unsigned char* expected, + const int expected_len) { + int frame_len = actual.length() + SpdyFrame::size(); + std::string actual_str(actual.data(), frame_len); + std::string expected_str(reinterpret_cast<const char*>(expected), + expected_len); + if (actual_str != expected_str) { + ADD_FAILURE() + << "Frame: " << description << "\n" + << "Expected:\n" << HexDump(expected, expected_len) << "\n" + << "Actual:\n" + HexDump( + reinterpret_cast<const unsigned char*>( + actual.data()), frame_len) << "\n"; + } + } }; // Test that we can encode and decode a SpdyHeaderBlock. @@ -636,5 +682,474 @@ TEST_F(SpdyFramerTest, UnclosedStreamDataCompressors) { EXPECT_EQ(0, send_framer.num_stream_decompressors()); } -} // namespace +TEST_F(SpdyFramerTest, CreateDataFrame) { + SpdyFramer framer; + + { + const char kDescription[] = "'hello' data frame, no FIN"; + const unsigned char kFrameData[] = { + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x05, + 'h', 'e', 'l', 'l', + 'o' + }; + scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( + 1, "hello", 5, DATA_FLAG_NONE)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = "Data frame with negative data byte, no FIN"; + const unsigned char kFrameData[] = { + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, + 0xff + }; + scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( + 1, "\xff", 1, DATA_FLAG_NONE)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = "'hello' data frame, with FIN"; + const unsigned char kFrameData[] = { + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x05, + 'h', 'e', 'l', 'l', + 'o' + }; + scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( + 1, "hello", 5, DATA_FLAG_FIN)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = "Empty data frame"; + const unsigned char kFrameData[] = { + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( + 1, "", 0, DATA_FLAG_NONE)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = "Data frame with max stream ID"; + const unsigned char kFrameData[] = { + 0x7f, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x05, + 'h', 'e', 'l', 'l', + 'o' + }; + scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( + 0x7fffffff, "hello", 5, DATA_FLAG_FIN)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } +} + +TEST_F(SpdyFramerTest, CreateSynStreamUncompressed) { + SpdyFramer framer; + FramerSetEnableCompressionHelper(&framer, false); + + { + const char kDescription[] = "SYN_STREAM frame, lowest pri, no FIN"; + + SpdyHeaderBlock headers; + headers["bar"] = "foo"; + headers["foo"] = "bar"; + + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0xC0, 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)); + } + + { + const char kDescription[] = + "SYN_STREAM frame with a 0-length header name, highest pri, FIN, " + "max stream ID"; + + SpdyHeaderBlock headers; + headers[""] = "foo"; + headers["foo"] = "bar"; + + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x1D, + 0x7f, 0xff, 0xff, 0xff, + 0x7f, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x03, + 'f', 'o', 'o', 0x00, + 0x03, 'f', 'o', 'o', + 0x00, 0x03, 'b', 'a', + 'r' + }; + scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( + 0x7fffffff, 0x7fffffff, SPDY_PRIORITY_HIGHEST, CONTROL_FLAG_FIN, + false, &headers)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = + "SYN_STREAM frame with a 0-length header val, highest pri, FIN, " + "max stream ID"; + + SpdyHeaderBlock headers; + headers["bar"] = "foo"; + headers["foo"] = ""; + + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x1D, + 0x7f, 0xff, 0xff, 0xff, + 0x7f, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, + 0x00, 0x03, 'b', 'a', + 'r', 0x00, 0x03, 'f', + 'o', 'o', 0x00, 0x03, + 'f', 'o', 'o', 0x00, + 0x00 + }; + scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( + 0x7fffffff, 0x7fffffff, SPDY_PRIORITY_HIGHEST, CONTROL_FLAG_FIN, + false, &headers)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } +} + +TEST_F(SpdyFramerTest, CreateSynStreamCompressed) { + SpdyFramer framer; + FramerSetEnableCompressionHelper(&framer, true); + { + const char kDescription[] = + "SYN_STREAM frame, lowest pri, no FIN"; + + SpdyHeaderBlock headers; + headers["bar"] = "foo"; + headers["foo"] = "bar"; + + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x25, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x38, 0xea, + 0xdf, 0xa2, 0x51, 0xb2, + 0x62, 0x60, 0x62, 0x60, + 0x4e, 0x4a, 0x2c, 0x62, + 0x60, 0x4e, 0xcb, 0xcf, + 0x87, 0x12, 0x40, 0x2e, + 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)); + } +} + +TEST_F(SpdyFramerTest, CreateSynReplyUncompressed) { + SpdyFramer framer; + FramerSetEnableCompressionHelper(&framer, false); + + { + const char kDescription[] = "SYN_REPLY frame, no FIN"; + + SpdyHeaderBlock headers; + headers["bar"] = "foo"; + headers["foo"] = "bar"; + + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x1C, + 0x00, 0x00, 0x00, 0x01, + 0x00, 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.CreateSynReply( + 1, CONTROL_FLAG_NONE, false, &headers)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = + "SYN_REPLY frame with a 0-length header name, FIN, max stream ID"; + + SpdyHeaderBlock headers; + headers[""] = "foo"; + headers["foo"] = "bar"; + + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x02, + 0x01, 0x00, 0x00, 0x19, + 0x7f, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x03, + 'f', 'o', 'o', 0x00, + 0x03, 'f', 'o', 'o', + 0x00, 0x03, 'b', 'a', + 'r' + }; + scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( + 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = + "SYN_REPLY frame with a 0-length header val, FIN, max stream ID"; + + SpdyHeaderBlock headers; + headers["bar"] = "foo"; + headers["foo"] = ""; + + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x02, + 0x01, 0x00, 0x00, 0x19, + 0x7f, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, + 0x00, 0x03, 'b', 'a', + 'r', 0x00, 0x03, 'f', + 'o', 'o', 0x00, 0x03, + 'f', 'o', 'o', 0x00, + 0x00 + }; + scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( + 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } +} + +TEST_F(SpdyFramerTest, CreateSynReplyCompressed) { + SpdyFramer framer; + FramerSetEnableCompressionHelper(&framer, true); + + { + const char kDescription[] = "SYN_REPLY frame, no FIN"; + + SpdyHeaderBlock headers; + headers["bar"] = "foo"; + headers["foo"] = "bar"; + + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x21, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x38, 0xea, + 0xdf, 0xa2, 0x51, 0xb2, + 0x62, 0x60, 0x62, 0x60, + 0x4e, 0x4a, 0x2c, 0x62, + 0x60, 0x4e, 0xcb, 0xcf, + 0x87, 0x12, 0x40, 0x2e, + 0x00, 0x00, 0x00, 0xff, + 0xff + }; + scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( + 1, CONTROL_FLAG_NONE, true, &headers)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } +} + +TEST_F(SpdyFramerTest, CreateRstStream) { + SpdyFramer framer; + + { + const char kDescription[] = "RST_STREAM frame"; + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(1, PROTOCOL_ERROR)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = "RST_STREAM frame with max stream ID"; + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x08, + 0x7f, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF, + PROTOCOL_ERROR)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = "RST_STREAM frame with max status code"; + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x08, + 0x7f, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x06, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF, + INTERNAL_ERROR)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } +} + +TEST_F(SpdyFramerTest, CreateSettings) { + SpdyFramer framer; + + { + 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)); + + // Duplicates allowed + settings.push_back(SpdySetting(0x01000002, 0x00000003)); + settings.push_back(SpdySetting(0x01000002, 0x00000003)); + + settings.push_back(SpdySetting(0x01000003, 0x000000ff)); + settings.push_back(SpdySetting(0x01000004, 0xff000001)); + settings.push_back(SpdySetting(0x01000004, 0xffffffff)); + + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x44, + 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, + 0xff, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, + 0x01, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x03, + 0x01, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x03, + 0x01, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0xff, + 0x01, 0x00, 0x00, 0x04, + 0xff, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x04, + 0xff, 0xff, 0xff, 0xff, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = "Empty SETTINGS frame"; + + SpdySettings settings; + + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } +} + +TEST_F(SpdyFramerTest, CreateNopFrame) { + SpdyFramer framer; + + { + const char kDescription[] = "NOOP frame"; + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x00, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateNopFrame()); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } +} + +TEST_F(SpdyFramerTest, CreateGoAway) { + SpdyFramer framer; + + { + const char kDescription[] = "GOAWAY frame"; + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = "GOAWAY frame with max stream ID"; + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x04, + 0x7f, 0xff, 0xff, 0xff, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } +} + +TEST_F(SpdyFramerTest, CreateWindowUpdate) { + SpdyFramer framer; + + { + const char kDescription[] = "WINDOW_UPDATE frame"; + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 1)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = "WINDOW_UPDATE frame with max stream ID"; + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x08, + 0x7f, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(0x7FFFFFFF, 1)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = "WINDOW_UPDATE frame with max window delta"; + const unsigned char kFrameData[] = { + 0x80, 0x01, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x01, + 0x80, 0x00, 0x00, 0x00, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x80000000)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } +} + +} // namespace diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h index 5bdc2b3..49d8bdc 100644 --- a/net/spdy/spdy_protocol.h +++ b/net/spdy/spdy_protocol.h @@ -183,7 +183,8 @@ enum SpdyStatusCodes { REFUSED_STREAM = 3, UNSUPPORTED_VERSION = 4, CANCEL = 5, - INTERNAL_ERROR = 6 + INTERNAL_ERROR = 6, + NUM_STATUS_CODES = 7 }; // A SPDY stream id is a 31 bit entity. @@ -534,8 +535,12 @@ class SpdyRstStreamControlFrame : public SpdyControlFrame { mutable_block()->stream_id_ = htonl(id & kStreamIdMask); } - uint32 status() const { return ntohl(block()->status_); } - void set_status(uint32 status) { mutable_block()->status_ = htonl(status); } + SpdyStatusCodes status() const { + return static_cast<SpdyStatusCodes>(ntohl(block()->status_)); + } + void set_status(SpdyStatusCodes status) { + mutable_block()->status_ = htonl(static_cast<uint32>(status)); + } // Returns the size of the SpdyRstStreamControlFrameBlock structure. // Note: this is not the size of the SpdyRstStreamControlFrame class. diff --git a/net/spdy/spdy_protocol_test.cc b/net/spdy/spdy_protocol_test.cc index 4aff242..e0b0591 100644 --- a/net/spdy/spdy_protocol_test.cc +++ b/net/spdy/spdy_protocol_test.cc @@ -31,6 +31,7 @@ using spdy::SpdyGoAwayControlFrame; using spdy::SpdyRstStreamControlFrame; using spdy::SpdySettings; using spdy::SpdySettingsControlFrame; +using spdy::SpdyStatusCodes; using spdy::SpdySynReplyControlFrame; using spdy::SpdySynStreamControlFrame; using spdy::SpdyWindowUpdateControlFrame; @@ -114,14 +115,14 @@ TEST(SpdyProtocolTest, ControlFrameStructs) { EXPECT_EQ(0, syn_reply->flags()); scoped_ptr<SpdyRstStreamControlFrame> rst_frame( - framer.CreateRstStream(123, 444)); + framer.CreateRstStream(123, spdy::PROTOCOL_ERROR)); EXPECT_EQ(kSpdyProtocolVersion, rst_frame->version()); EXPECT_TRUE(rst_frame->is_control_frame()); EXPECT_EQ(RST_STREAM, rst_frame->type()); EXPECT_EQ(123u, rst_frame->stream_id()); - EXPECT_EQ(444u, rst_frame->status()); - rst_frame->set_status(555); - EXPECT_EQ(555u, rst_frame->status()); + EXPECT_EQ(spdy::PROTOCOL_ERROR, rst_frame->status()); + rst_frame->set_status(spdy::INVALID_STREAM); + EXPECT_EQ(spdy::INVALID_STREAM, rst_frame->status()); EXPECT_EQ(0, rst_frame->flags()); scoped_ptr<SpdyGoAwayControlFrame> goaway_frame( |