diff options
author | mbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-03 22:04:03 +0000 |
---|---|---|
committer | mbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-03 22:04:03 +0000 |
commit | d083585002893abaa6172c361aa04306a0e4d396 (patch) | |
tree | 75ff77ddf51d68d450ee0e7d56192409e44bcf97 /net/spdy/spdy_framer_test.cc | |
parent | 95c97199c4406036b216d74e4ba3a5c57c0081a2 (diff) | |
download | chromium_src-d083585002893abaa6172c361aa04306a0e4d396.zip chromium_src-d083585002893abaa6172c361aa04306a0e4d396.tar.gz chromium_src-d083585002893abaa6172c361aa04306a0e4d396.tar.bz2 |
Update server push to allow use of HEADERS frame.
- Sync'd server changes for SPDY protocol and framer.
- Adds HEADERS support & smaller header frame support.
- Changes field name from "path" to "url" for pushed streams.
- Changes existing semantics in SpdyStream and SpdyHttpStream
with how the OnResponseReceived callback works and with how
headers are parsed to reflect multi-frame arrival of headers.
Other changes:
- Reworked the StaticSocketDataProvider interface slightly so that we
can share code between tests using DelayedSocketData or
DeterministicSocketData
- Tidy up net_log for pushed streams with associated-stream id logging
and format fixes for SPDY_STREAM.
BUG=none
TEST=spdy_framer_test,spdy_network_transaction_unittest(s)
Review URL: http://codereview.chromium.org/5248001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68221 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/spdy/spdy_framer_test.cc')
-rw-r--r-- | net/spdy/spdy_framer_test.cc | 208 |
1 files changed, 205 insertions, 3 deletions
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc index d238062..b4345c1 100644 --- a/net/spdy/spdy_framer_test.cc +++ b/net/spdy/spdy_framer_test.cc @@ -86,6 +86,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface { : error_count_(0), syn_frame_count_(0), syn_reply_frame_count_(0), + headers_frame_count_(0), data_bytes_(0), fin_frame_count_(0), fin_flag_count_(0), @@ -129,6 +130,11 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface { case RST_STREAM: fin_frame_count_++; break; + case HEADERS: + parsed_headers = framer_.ParseHeaderBlock(frame, &headers); + DCHECK(parsed_headers); + headers_frame_count_++; + break; default: DCHECK(false); // Error! } @@ -163,6 +169,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface { int error_count_; int syn_frame_count_; int syn_reply_frame_count_; + int headers_frame_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. @@ -264,7 +271,6 @@ TEST_F(SpdyFramerTest, WrongNumberOfHeaders) { frame1.WriteUInt16(SYN_STREAM); frame1.WriteUInt32(0); // Placeholder for the length. frame1.WriteUInt32(3); // stream_id - frame1.WriteUInt32(0); // associated stream id frame1.WriteUInt16(0); // Priority. frame1.WriteUInt16(1); // Wrong number of headers (underflow) @@ -280,7 +286,6 @@ TEST_F(SpdyFramerTest, WrongNumberOfHeaders) { frame2.WriteUInt16(SYN_STREAM); frame2.WriteUInt32(0); // Placeholder for the length. frame2.WriteUInt32(3); // stream_id - frame2.WriteUInt32(0); // associated stream id frame2.WriteUInt16(0); // Priority. frame2.WriteUInt16(100); // Wrong number of headers (overflow) @@ -446,6 +451,15 @@ TEST_F(SpdyFramerTest, Basic) { 0x00, 0x02, 'h', 'h', 0x00, 0x02, 'v', 'v', + 0x80, 0x02, 0x00, 0x08, // HEADERS on Stream #1 + 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, + 0x00, 0x02, 'h', '2', + 0x00, 0x02, 'v', '2', + 0x00, 0x02, 'h', '3', + 0x00, 0x02, 'v', '3', + 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 0x00, 0x00, 0x00, 0x0c, 0xde, 0xad, 0xbe, 0xef, @@ -487,6 +501,7 @@ TEST_F(SpdyFramerTest, Basic) { EXPECT_EQ(0, visitor.error_count_); EXPECT_EQ(2, visitor.syn_frame_count_); EXPECT_EQ(0, visitor.syn_reply_frame_count_); + EXPECT_EQ(1, visitor.headers_frame_count_); EXPECT_EQ(24, visitor.data_bytes_); EXPECT_EQ(2, visitor.fin_frame_count_); EXPECT_EQ(0, visitor.fin_flag_count_); @@ -528,6 +543,7 @@ TEST_F(SpdyFramerTest, FinOnDataFrame) { EXPECT_EQ(0, visitor.error_count_); EXPECT_EQ(1, visitor.syn_frame_count_); EXPECT_EQ(1, visitor.syn_reply_frame_count_); + EXPECT_EQ(0, visitor.headers_frame_count_); EXPECT_EQ(16, visitor.data_bytes_); EXPECT_EQ(0, visitor.fin_frame_count_); EXPECT_EQ(0, visitor.fin_flag_count_); @@ -559,6 +575,7 @@ TEST_F(SpdyFramerTest, FinOnSynReplyFrame) { EXPECT_EQ(0, visitor.error_count_); EXPECT_EQ(1, visitor.syn_frame_count_); EXPECT_EQ(1, visitor.syn_reply_frame_count_); + EXPECT_EQ(0, visitor.headers_frame_count_); EXPECT_EQ(0, visitor.data_bytes_); EXPECT_EQ(0, visitor.fin_frame_count_); EXPECT_EQ(1, visitor.fin_flag_count_); @@ -683,7 +700,9 @@ TEST_F(SpdyFramerTest, UnclosedStreamDataCompressors) { const char bytes[] = "this is a test test test test test!"; scoped_ptr<SpdyFrame> send_frame( - send_framer.CreateDataFrame(1, bytes, arraysize(bytes), + send_framer.CreateDataFrame(1, + bytes, + arraysize(bytes), DATA_FLAG_FIN)); EXPECT_TRUE(send_frame.get() != NULL); @@ -698,6 +717,7 @@ TEST_F(SpdyFramerTest, UnclosedStreamDataCompressors) { 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_); @@ -1140,6 +1160,112 @@ TEST_F(SpdyFramerTest, CreateGoAway) { } } +TEST_F(SpdyFramerTest, CreateHeadersUncompressed) { + SpdyFramer framer; + FramerSetEnableCompressionHelper(&framer, false); + + { + const char kDescription[] = "HEADERS frame, no FIN"; + + SpdyHeaderBlock headers; + headers["bar"] = "foo"; + headers["foo"] = "bar"; + + const unsigned char kFrameData[] = { + 0x80, 0x02, 0x00, 0x08, + 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.CreateHeaders( + 1, CONTROL_FLAG_NONE, false, &headers)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = + "HEADERS frame with a 0-length header name, FIN, max stream ID"; + + SpdyHeaderBlock headers; + headers[""] = "foo"; + headers["foo"] = "bar"; + + const unsigned char kFrameData[] = { + 0x80, 0x02, 0x00, 0x08, + 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.CreateHeaders( + 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } + + { + const char kDescription[] = + "HEADERS frame with a 0-length header val, FIN, max stream ID"; + + SpdyHeaderBlock headers; + headers["bar"] = "foo"; + headers["foo"] = ""; + + const unsigned char kFrameData[] = { + 0x80, 0x02, 0x00, 0x08, + 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.CreateHeaders( + 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } +} + +TEST_F(SpdyFramerTest, CreateHeadersCompressed) { + SpdyFramer framer; + FramerSetEnableCompressionHelper(&framer, true); + + { + const char kDescription[] = "HEADERS frame, no FIN"; + + SpdyHeaderBlock headers; + headers["bar"] = "foo"; + headers["foo"] = "bar"; + + const unsigned char kFrameData[] = { + 0x80, 0x02, 0x00, 0x08, + 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.CreateHeaders( + 1, CONTROL_FLAG_NONE, true, &headers)); + CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + } +} + TEST_F(SpdyFramerTest, CreateWindowUpdate) { SpdyFramer framer; @@ -1180,4 +1306,80 @@ TEST_F(SpdyFramerTest, CreateWindowUpdate) { } } +// This test case reproduces conditions that caused ExpandControlFrameBuffer to +// fail to expand the buffer control frame buffer when it should have, allowing +// 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) { + // 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; + val2_len < SpdyFramer::kControlFrameBufferInitialSize; + val2_len++) { + std::string val2 = std::string(val2_len, 'a'); + SpdyHeaderBlock headers; + headers["bar"] = "foo"; + headers["foo"] = "baz"; + headers["grue"] = val2.c_str(); + SpdyFramer framer; + scoped_ptr<SpdySynStreamControlFrame> template_frame( + framer.CreateSynStream(1, // stream_id + 0, // associated_stream_id + 1, // priority + CONTROL_FLAG_NONE, + false, // compress + &headers)); + EXPECT_TRUE(template_frame.get() != NULL); + TestSpdyVisitor visitor; + visitor.SimulateInFramer( + reinterpret_cast<unsigned char*>(template_frame.get()->data()), + template_frame.get()->length() + SpdyControlFrame::size()); + EXPECT_EQ(1, visitor.syn_frame_count_); + } +} + +std::string RandomString(int length) { + std::string rv; + for (int index = 0; index < length; index++) + rv += static_cast<char>('a' + (rand() % 26)); + return rv; +} + +// Stress that we can handle a really large header block compression and +// decompression. +TEST_F(SpdyFramerTest, HugeHeaderBlock) { + // Loop targetting various sizes which will potentially jam up the + // frame compressor/decompressor. + SpdyFramer compress_framer; + SpdyFramer decompress_framer; + for (size_t target_size = 1024; + target_size < SpdyFramer::kControlFrameBufferInitialSize; + target_size += 1024) { + SpdyHeaderBlock headers; + for (size_t index = 0; index < target_size; ++index) { + std::string name = RandomString(4); + std::string value = RandomString(8); + headers[name] = value; + } + + // Encode the header block into a SynStream frame. + scoped_ptr<SpdySynStreamControlFrame> frame( + compress_framer.CreateSynStream(1, + 0, + 1, + CONTROL_FLAG_NONE, + true, + &headers)); + // The point of this test is to exercise the limits. So, it is ok if the + // frame was too large to encode, or if the decompress fails. We just want + // to make sure we don't crash. + if (frame.get() != NULL) { + // Now that same header block should decompress just fine. + SpdyHeaderBlock new_headers; + decompress_framer.ParseHeaderBlock(frame.get(), &new_headers); + } + } +} + } // namespace |