Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(545)

Unified Diff: net/spdy/spdy_framer_test.cc

Issue 10164020: Add a number of tests to spdy_framer_test.cc from server code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/spdy/spdy_framer_test.cc
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 927953980a9bda94bdd058f0d2cb3f6f487508c6..410fea4b83031786eeb4ac7a046c14b52eb2af8d 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -400,7 +400,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface {
}
static size_t control_frame_buffer_max_size() {
- return SpdyFramer::kControlFrameBufferSize;
+ return SpdyFramer::kMaxControlFrameSize;
}
static size_t header_data_chunk_max_size() {
@@ -2236,6 +2236,245 @@ TEST_P(SpdyFramerTest, DuplicateFrame) {
}
}
+TEST_P(SpdyFramerTest, ReadCompressedSynStreamHeaderBlock) {
+ SpdyHeaderBlock headers;
+ headers["aa"] = "vv";
+ headers["bb"] = "ww";
+ SpdyFramer framer(spdy_version_);
+ scoped_ptr<SpdySynStreamControlFrame> control_frame(
+ framer.CreateSynStream(1, // stream_id
+ 0, // associated_stream_id
+ 1, // priority
+ 0, // credential_slot
+ CONTROL_FLAG_NONE,
+ true, // compress
+ &headers));
+ EXPECT_TRUE(control_frame.get() != NULL);
+ TestSpdyVisitor visitor(spdy_version_);
+ visitor.use_compression_ = true;
+ visitor.SimulateInFramer(
+ reinterpret_cast<unsigned char*>(control_frame->data()),
+ control_frame->length() + SpdyControlFrame::kHeaderSize);
+ EXPECT_EQ(1, visitor.syn_frame_count_);
+ EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
+}
+
+TEST_P(SpdyFramerTest, ReadCompressedSynReplyHeaderBlock) {
+ SpdyHeaderBlock headers;
+ headers["alpha"] = "beta";
+ headers["gamma"] = "delta";
+ SpdyFramer framer(spdy_version_);
+ scoped_ptr<SpdySynReplyControlFrame> control_frame(
+ framer.CreateSynReply(1, // stream_id
+ CONTROL_FLAG_NONE,
+ true, // compress
+ &headers));
+ EXPECT_TRUE(control_frame.get() != NULL);
+ TestSpdyVisitor visitor(spdy_version_);
+ visitor.use_compression_ = true;
+ visitor.SimulateInFramer(
+ reinterpret_cast<unsigned char*>(control_frame->data()),
+ control_frame.get()->length() + SpdyControlFrame::kHeaderSize);
+ EXPECT_EQ(1, visitor.syn_reply_frame_count_);
+ EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
+}
+
+TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) {
+ SpdyHeaderBlock headers;
+ headers["alpha"] = "beta";
+ headers["gamma"] = "delta";
+ SpdyFramer framer(spdy_version_);
+ scoped_ptr<SpdyHeadersControlFrame> control_frame(
+ framer.CreateHeaders(1, // stream_id
+ CONTROL_FLAG_NONE,
+ true, // compress
+ &headers));
+ EXPECT_TRUE(control_frame.get() != NULL);
+ TestSpdyVisitor visitor(spdy_version_);
+ visitor.use_compression_ = true;
+ visitor.SimulateInFramer(
+ reinterpret_cast<unsigned char*>(control_frame->data()),
+ control_frame.get()->length() + SpdyControlFrame::kHeaderSize);
+ EXPECT_EQ(1, visitor.headers_frame_count_);
+ // control_frame_header_data_count_ depends on the random sequence
+ // produced by rand(), so adding, removing or running single tests
+ // alters this value. The best we can do is assert that it happens
+ // at least twice.
+ EXPECT_LE(2, visitor.control_frame_header_data_count_);
+ EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
+ EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
+ EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
+}
+
+TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) {
+ SpdyHeaderBlock headers;
+ headers["alpha"] = "beta";
+ headers["gamma"] = "delta";
+ SpdyFramer framer(spdy_version_);
+ scoped_ptr<SpdyHeadersControlFrame> control_frame(
+ framer.CreateHeaders(1, // stream_id
+ CONTROL_FLAG_FIN,
+ true, // compress
+ &headers));
+ EXPECT_TRUE(control_frame.get() != NULL);
+ TestSpdyVisitor visitor(spdy_version_);
+ visitor.use_compression_ = true;
+ visitor.SimulateInFramer(
+ reinterpret_cast<unsigned char*>(control_frame->data()),
+ control_frame->length() + SpdyControlFrame::kHeaderSize);
+ EXPECT_EQ(1, visitor.headers_frame_count_);
+ // control_frame_header_data_count_ depends on the random sequence
+ // produced by rand(), so adding, removing or running single tests
+ // alters this value. The best we can do is assert that it happens
+ // at least twice.
+ EXPECT_LE(2, visitor.control_frame_header_data_count_);
+ EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
+ EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
+ EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
+}
+
+TEST_P(SpdyFramerTest, ControlFrameAtMaxSizeLimit) {
+ SpdyHeaderBlock headers;
+ // Size a header value to just fit inside the control frame buffer:
+ // SPDY 2 SPDY 3
+ // SYN_STREAM header: 18 bytes 18 bytes
+ // Serialized header block:
+ // # headers 2 bytes (uint16) 4 bytes (uint32)
+ // name length 2 bytes (uint16) 4 bytes (uint32)
+ // name text ("aa") 2 bytes 2 bytes
+ // value length 2 bytes (uint16) 4 bytes (uint32)
+ // --- ---
+ // 26 bytes 32 bytes
+ const size_t overhead = IsSpdy2() ? 26 : 32;
+ const size_t big_value_size =
+ TestSpdyVisitor::control_frame_buffer_max_size() - overhead;
+ std::string big_value(big_value_size, 'x');
+ headers["aa"] = big_value.c_str();
+ SpdyFramer framer(spdy_version_);
+ scoped_ptr<SpdySynStreamControlFrame> control_frame(
+ framer.CreateSynStream(1, // stream_id
+ 0, // associated_stream_id
+ 1, // priority
+ 0, // credential_slot
+ CONTROL_FLAG_NONE,
+ false, // compress
+ &headers));
+ EXPECT_TRUE(control_frame.get() != NULL);
+ TestSpdyVisitor visitor(spdy_version_);
+ visitor.SimulateInFramer(
+ reinterpret_cast<unsigned char*>(control_frame->data()),
+ control_frame->length() + SpdyControlFrame::kHeaderSize);
+ EXPECT_TRUE(visitor.header_buffer_valid_);
+ EXPECT_EQ(0, visitor.error_count_);
+ EXPECT_EQ(1, visitor.syn_frame_count_);
+ EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
+ EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
+ EXPECT_LT(big_value_size, visitor.header_buffer_length_);
+}
+
+TEST_P(SpdyFramerTest, ControlFrameTooLarge) {
+ SpdyHeaderBlock headers;
+ // See size calculation for test above. This is one byte larger, which
+ // should exceed the control frame buffer capacity by that one byte.
+ const size_t overhead = IsSpdy2() ? 25 : 31;
+ const size_t kBigValueSize =
+ TestSpdyVisitor::control_frame_buffer_max_size() - overhead;
+ std::string big_value(kBigValueSize, 'x');
+ headers["aa"] = big_value.c_str();
+ SpdyFramer framer(spdy_version_);
+ scoped_ptr<SpdySynStreamControlFrame> control_frame(
+ framer.CreateSynStream(1, // stream_id
+ 0, // associated_stream_id
+ 1, // priority
+ 0, // credential_slot
+ CONTROL_FLAG_NONE,
+ false, // compress
+ &headers));
+ EXPECT_TRUE(control_frame.get() != NULL);
+ TestSpdyVisitor visitor(spdy_version_);
+ visitor.SimulateInFramer(
+ reinterpret_cast<unsigned char*>(control_frame->data()),
+ control_frame.get()->length() + SpdyControlFrame::kHeaderSize);
+ EXPECT_FALSE(visitor.header_buffer_valid_);
+ EXPECT_EQ(1, visitor.error_count_);
+ EXPECT_EQ(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE,
+ visitor.framer_.error_code());
+ EXPECT_EQ(0, visitor.syn_frame_count_);
+ EXPECT_EQ(0u, visitor.header_buffer_length_);
+}
+
+// Check that the framer stops delivering header data chunks once the visitor
+// declares it doesn't want any more. This is important to guard against
+// "zip bomb" types of attacks.
+TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) {
+ SpdyHeaderBlock headers;
+ const size_t kHeaderBufferChunks = 4;
+ const size_t kHeaderBufferSize =
+ TestSpdyVisitor::header_data_chunk_max_size() * kHeaderBufferChunks;
+ const size_t big_value_size = kHeaderBufferSize * 2;
+ std::string big_value(big_value_size, 'x');
+ headers["aa"] = big_value.c_str();
+ SpdyFramer framer(spdy_version_);
+ scoped_ptr<SpdySynStreamControlFrame> control_frame(
+ framer.CreateSynStream(1, // stream_id
+ 0, // associated_stream_id
+ 1, // priority
+ 0, // credential_slot
+ CONTROL_FLAG_FIN, // half close
+ true, // compress
+ &headers));
+ EXPECT_TRUE(control_frame.get() != NULL);
+ TestSpdyVisitor visitor(spdy_version_);
+ visitor.set_header_buffer_size(kHeaderBufferSize);
+ visitor.use_compression_ = true;
+ visitor.SimulateInFramer(
+ reinterpret_cast<unsigned char*>(control_frame->data()),
+ control_frame->length() + SpdyControlFrame::kHeaderSize);
+ EXPECT_FALSE(visitor.header_buffer_valid_);
+ EXPECT_EQ(1, visitor.error_count_);
+ EXPECT_EQ(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE,
+ visitor.framer_.error_code());
+
+ // The framer should have stoped delivering chunks after the visitor
+ // signaled "stop" by returning false from OnControlFrameHeaderData().
+ //
+ // control_frame_header_data_count_ depends on the random sequence
+ // produced by rand(), so adding, removing or running single tests
+ // alters this value. The best we can do is assert that it happens
+ // at least kHeaderBufferChunks + 1.
+ EXPECT_LE(kHeaderBufferChunks + 1,
+ static_cast<unsigned>(visitor.control_frame_header_data_count_));
+ EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
+
+ // The framer should not have sent half-close to the visitor.
+ EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
+}
+
+TEST_P(SpdyFramerTest, DecompressCorruptHeaderBlock) {
+ SpdyHeaderBlock headers;
+ headers["aa"] = "alpha beta gamma delta";
+ SpdyFramer framer(spdy_version_);
+ // Construct a SYN_STREAM control frame without compressing the header block,
+ // and have the framer try to decompress it. This will cause the framer to
+ // deal with a decompression error.
+ scoped_ptr<SpdySynStreamControlFrame> control_frame(
+ framer.CreateSynStream(1, // stream_id
+ 0, // associated_stream_id
+ 1, // priority
+ 0, // credential_slot
+ CONTROL_FLAG_NONE,
+ false, // compress
+ &headers));
+ TestSpdyVisitor visitor(spdy_version_);
+ visitor.use_compression_ = true;
+ visitor.SimulateInFramer(
+ reinterpret_cast<unsigned char*>(control_frame->data()),
+ control_frame->length() + SpdyControlFrame::kHeaderSize);
+ EXPECT_EQ(1, visitor.error_count_);
+ EXPECT_EQ(SpdyFramer::SPDY_DECOMPRESS_FAILURE, visitor.framer_.error_code());
+ EXPECT_EQ(0u, visitor.header_buffer_length_);
+}
+
TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) {
// Create a GoAway frame that has a few extra bytes at the end.
// We create enough overhead to overflow the framer's control frame buffer.
@@ -2361,6 +2600,59 @@ TEST_P(SpdyFramerTest, ReadCredentialFrame) {
}
}
+TEST_P(SpdyFramerTest, ReadCredentialFrameOneByteAtATime) {
+ 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(spdy_version_);
+ scoped_ptr<SpdyFrame> control_frame(
+ framer.CreateCredentialFrame(credential));
+ EXPECT_TRUE(control_frame.get() != NULL);
+ TestSpdyVisitor visitor(spdy_version_);
+ visitor.use_compression_ = false;
+ // Read one byte at a time to make sure we handle edge cases
+ unsigned char* data =
+ reinterpret_cast<unsigned char*>(control_frame->data());
+ for (size_t idx = 0;
+ idx < control_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.credential_count_);
+ EXPECT_EQ(control_frame->length(), visitor.credential_buffer_length_);
+ EXPECT_EQ(credential.slot, visitor.credential_.slot);
+ EXPECT_EQ(credential.proof, visitor.credential_.proof);
+ EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size());
+ for (size_t i = 0; i < credential.certs.size(); i++) {
+ EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]);
+ }
+}
+
+TEST_P(SpdyFramerTest, ReadCredentialFrameWithNoPayload) {
+ 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(spdy_version_);
+ scoped_ptr<SpdyFrame> control_frame(
+ framer.CreateCredentialFrame(credential));
+ EXPECT_TRUE(control_frame.get() != NULL);
+ TestSpdyVisitor visitor(spdy_version_);
+ visitor.use_compression_ = false;
+ control_frame->set_length(0);
+ unsigned char* data =
+ reinterpret_cast<unsigned char*>(control_frame->data());
+ visitor.SimulateInFramer(data, SpdyControlFrame::kHeaderSize);
+ EXPECT_EQ(1, visitor.error_count_);
+}
+
TEST_P(SpdyFramerTest, ReadCredentialFrameWithCorruptProof) {
SpdyCredential credential;
credential.slot = 3;
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698