summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authormlloyd@chromium.org <mlloyd@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-08 20:50:13 +0000
committermlloyd@chromium.org <mlloyd@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-08 20:50:13 +0000
commite9eeaf55115c9ac8bb991d318b4427beee69e735 (patch)
treec491c5506ecb583ca9cdae84c7e92fbde2287707 /net
parenta13e022a717bd7d9e43681aafd4201573bcd3147 (diff)
downloadchromium_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.h6
-rw-r--r--net/spdy/spdy_framer.cc51
-rw-r--r--net/spdy/spdy_framer.h4
-rw-r--r--net/spdy/spdy_framer_test.cc517
-rw-r--r--net/spdy/spdy_protocol.h11
-rw-r--r--net/spdy/spdy_protocol_test.cc9
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(