| Index: net/spdy/spdy_framer_test.cc
|
| diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
|
| index c09e86174fdc32d6220405ee7925e30cb548b2d7..6205bb8baefd901c9782f7fa9576d4ad6f88fdc1 100644
|
| --- a/net/spdy/spdy_framer_test.cc
|
| +++ b/net/spdy/spdy_framer_test.cc
|
| @@ -222,6 +222,8 @@ class SpdyFramerTestUtil {
|
| class TestSpdyVisitor : public SpdyFramerVisitorInterface,
|
| public SpdyFramerDebugVisitorInterface {
|
| public:
|
| + // This is larger than our max frame size because header blocks that
|
| + // are too long can spill over into CONTINUATION frames.
|
| static const size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024;
|
|
|
| explicit TestSpdyVisitor(SpdyMajorVersion version)
|
| @@ -231,6 +233,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
|
| syn_frame_count_(0),
|
| syn_reply_frame_count_(0),
|
| headers_frame_count_(0),
|
| + push_promise_frame_count_(0),
|
| goaway_count_(0),
|
| setting_count_(0),
|
| settings_ack_sent_(0),
|
| @@ -261,13 +264,13 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
|
| virtual void OnError(SpdyFramer* f) OVERRIDE {
|
| LOG(INFO) << "SpdyFramer Error: "
|
| << SpdyFramer::ErrorCodeToString(f->error_code());
|
| - error_count_++;
|
| + ++error_count_;
|
| }
|
|
|
| virtual void OnDataFrameHeader(SpdyStreamId stream_id,
|
| size_t length,
|
| bool fin) OVERRIDE {
|
| - data_frame_count_++;
|
| + ++data_frame_count_;
|
| header_stream_id_ = stream_id;
|
| }
|
|
|
| @@ -321,24 +324,24 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
|
| SpdyPriority priority,
|
| bool fin,
|
| bool unidirectional) OVERRIDE {
|
| - syn_frame_count_++;
|
| + ++syn_frame_count_;
|
| InitHeaderStreaming(SYN_STREAM, stream_id);
|
| if (fin) {
|
| - fin_flag_count_++;
|
| + ++fin_flag_count_;
|
| }
|
| }
|
|
|
| virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {
|
| - syn_reply_frame_count_++;
|
| + ++syn_reply_frame_count_;
|
| InitHeaderStreaming(SYN_REPLY, stream_id);
|
| if (fin) {
|
| - fin_flag_count_++;
|
| + ++fin_flag_count_;
|
| }
|
| }
|
|
|
| virtual void OnRstStream(SpdyStreamId stream_id,
|
| SpdyRstStreamStatus status) OVERRIDE {
|
| - fin_frame_count_++;
|
| + ++fin_frame_count_;
|
| }
|
|
|
| virtual bool OnRstStreamFrameData(const char* rst_stream_data,
|
| @@ -352,17 +355,17 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
|
| virtual void OnSetting(SpdySettingsIds id,
|
| uint8 flags,
|
| uint32 value) OVERRIDE {
|
| - setting_count_++;
|
| + ++setting_count_;
|
| }
|
|
|
| virtual void OnSettingsAck() OVERRIDE {
|
| DCHECK_GE(4, framer_.protocol_version());
|
| - settings_ack_received_++;
|
| + ++settings_ack_received_;
|
| }
|
|
|
| virtual void OnSettingsEnd() OVERRIDE {
|
| if (framer_.protocol_version() < 4) { return; }
|
| - settings_ack_sent_++;
|
| + ++settings_ack_sent_;
|
| }
|
|
|
| virtual void OnPing(SpdyPingId unique_id, bool is_ack) OVERRIDE {
|
| @@ -371,14 +374,14 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
|
|
|
| virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
|
| SpdyGoAwayStatus status) OVERRIDE {
|
| - goaway_count_++;
|
| + ++goaway_count_;
|
| }
|
|
|
| virtual void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) OVERRIDE {
|
| - headers_frame_count_++;
|
| + ++headers_frame_count_;
|
| InitHeaderStreaming(HEADERS, stream_id);
|
| if (fin) {
|
| - fin_flag_count_++;
|
| + ++fin_flag_count_;
|
| }
|
| }
|
|
|
| @@ -391,13 +394,14 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
|
| virtual void OnPushPromise(SpdyStreamId stream_id,
|
| SpdyStreamId promised_stream_id,
|
| bool end) OVERRIDE {
|
| + ++push_promise_frame_count_;
|
| InitHeaderStreaming(PUSH_PROMISE, stream_id);
|
| last_push_promise_stream_ = stream_id;
|
| last_push_promise_promised_stream_ = promised_stream_id;
|
| }
|
|
|
| virtual void OnContinuation(SpdyStreamId stream_id, bool end) OVERRIDE {
|
| - continuation_count_++;
|
| + ++continuation_count_;
|
| }
|
|
|
| virtual void OnSendCompressedFrame(SpdyStreamId stream_id,
|
| @@ -464,6 +468,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
|
| int syn_frame_count_;
|
| int syn_reply_frame_count_;
|
| int headers_frame_count_;
|
| + int push_promise_frame_count_;
|
| int goaway_count_;
|
| int setting_count_;
|
| int settings_ack_sent_;
|
| @@ -695,16 +700,16 @@ TEST_P(SpdyFramerTest, RejectUpperCaseHeaderBlockValue) {
|
| SpdyFramer framer(spdy_version_);
|
| framer.set_enable_compression(false);
|
|
|
| - SpdyFrameBuilder frame(1024);
|
| - frame.WriteFramePrefix(framer, HEADERS, HEADERS_FLAG_PRIORITY, 1);
|
| + SpdyFrameBuilder frame(1024, spdy_version_);
|
| + frame.BeginNewFrame(framer, HEADERS, HEADERS_FLAG_PRIORITY, 1);
|
| frame.WriteUInt32(framer.GetHighestPriority());
|
| frame.WriteUInt32(1);
|
| frame.WriteStringPiece32("Name1");
|
| frame.WriteStringPiece32("value1");
|
| frame.RewriteLength(framer);
|
|
|
| - SpdyFrameBuilder frame2(1024);
|
| - frame2.WriteFramePrefix(framer, HEADERS, 0, 1);
|
| + SpdyFrameBuilder frame2(1024, spdy_version_);
|
| + frame2.BeginNewFrame(framer, HEADERS, 0, 1);
|
| frame2.WriteUInt32(2);
|
| frame2.WriteStringPiece32("name1");
|
| frame2.WriteStringPiece32("value1");
|
| @@ -836,14 +841,14 @@ TEST_P(SpdyFramerTest, DuplicateHeader) {
|
| }
|
| SpdyFramer framer(spdy_version_);
|
| // Frame builder with plentiful buffer size.
|
| - SpdyFrameBuilder frame(1024);
|
| + SpdyFrameBuilder frame(1024, spdy_version_);
|
| if (spdy_version_ < 4) {
|
| frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
|
| frame.WriteUInt32(3); // stream_id
|
| frame.WriteUInt32(0); // associated stream id
|
| frame.WriteUInt16(0); // Priority.
|
| } else {
|
| - frame.WriteFramePrefix(framer, HEADERS, HEADERS_FLAG_PRIORITY, 3);
|
| + frame.BeginNewFrame(framer, HEADERS, HEADERS_FLAG_PRIORITY, 3);
|
| frame.WriteUInt32(framer.GetHighestPriority());
|
| }
|
|
|
| @@ -877,17 +882,17 @@ TEST_P(SpdyFramerTest, DuplicateHeader) {
|
| TEST_P(SpdyFramerTest, MultiValueHeader) {
|
| SpdyFramer framer(spdy_version_);
|
| // Frame builder with plentiful buffer size.
|
| - SpdyFrameBuilder frame(1024);
|
| + SpdyFrameBuilder frame(1024, spdy_version_);
|
| if (spdy_version_ < 4) {
|
| frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
|
| frame.WriteUInt32(3); // stream_id
|
| frame.WriteUInt32(0); // associated stream id
|
| frame.WriteUInt16(0); // Priority.
|
| } else {
|
| - frame.WriteFramePrefix(framer,
|
| - HEADERS,
|
| - HEADERS_FLAG_PRIORITY | HEADERS_FLAG_END_HEADERS,
|
| - 3);
|
| + frame.BeginNewFrame(framer,
|
| + HEADERS,
|
| + HEADERS_FLAG_PRIORITY | HEADERS_FLAG_END_HEADERS,
|
| + 3);
|
| frame.WriteUInt32(framer.GetHighestPriority());
|
| }
|
|
|
| @@ -3140,6 +3145,63 @@ TEST_P(SpdyFramerTest, ControlFrameTooLarge) {
|
| EXPECT_EQ(0u, visitor.header_buffer_length_);
|
| }
|
|
|
| +TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) {
|
| + if (spdy_version_ < net::SPDY4) {
|
| + return;
|
| + }
|
| + SpdyFramer framer(spdy_version_);
|
| + framer.set_enable_compression(false);
|
| + SpdyHeadersIR headers(1);
|
| +
|
| + // Exact payload length will change with HPACK, but this should be long
|
| + // enough to cause an overflow.
|
| + const size_t kBigValueSize = framer.GetControlFrameBufferMaxSize();
|
| + string big_value(kBigValueSize, 'x');
|
| + headers.SetHeader("aa", big_value.c_str());
|
| + scoped_ptr<SpdyFrame> control_frame(framer.SerializeHeaders(headers));
|
| + EXPECT_TRUE(control_frame.get() != NULL);
|
| + EXPECT_GT(control_frame->size(), framer.GetControlFrameBufferMaxSize());
|
| +
|
| + TestSpdyVisitor visitor(spdy_version_);
|
| + visitor.SimulateInFramer(
|
| + reinterpret_cast<unsigned char*>(control_frame->data()),
|
| + control_frame->size());
|
| + EXPECT_TRUE(visitor.header_buffer_valid_);
|
| + EXPECT_EQ(0, visitor.error_count_);
|
| + EXPECT_EQ(1, visitor.headers_frame_count_);
|
| + EXPECT_EQ(1, visitor.continuation_count_);
|
| + EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
|
| +}
|
| +
|
| +TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) {
|
| + if (spdy_version_ < net::SPDY4) {
|
| + return;
|
| + }
|
| + SpdyFramer framer(spdy_version_);
|
| + framer.set_enable_compression(false);
|
| + SpdyPushPromiseIR push_promise(1, 2);
|
| +
|
| + // Exact payload length will change with HPACK, but this should be long
|
| + // enough to cause an overflow.
|
| + const size_t kBigValueSize = framer.GetControlFrameBufferMaxSize();
|
| + string big_value(kBigValueSize, 'x');
|
| + push_promise.SetHeader("aa", big_value.c_str());
|
| + scoped_ptr<SpdyFrame> control_frame(
|
| + framer.SerializePushPromise(push_promise));
|
| + EXPECT_TRUE(control_frame.get() != NULL);
|
| + EXPECT_GT(control_frame->size(), framer.GetControlFrameBufferMaxSize());
|
| +
|
| + TestSpdyVisitor visitor(spdy_version_);
|
| + visitor.SimulateInFramer(
|
| + reinterpret_cast<unsigned char*>(control_frame->data()),
|
| + control_frame->size());
|
| + EXPECT_TRUE(visitor.header_buffer_valid_);
|
| + EXPECT_EQ(0, visitor.error_count_);
|
| + EXPECT_EQ(1, visitor.push_promise_frame_count_);
|
| + EXPECT_EQ(1, visitor.continuation_count_);
|
| + EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
|
| +}
|
| +
|
| // 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.
|
|
|