diff options
author | rtenneti@google.com <rtenneti@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-22 04:11:22 +0000 |
---|---|---|
committer | rtenneti@google.com <rtenneti@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-22 04:11:22 +0000 |
commit | 073487ed936883ccd581b224c2c6cc6264abbf1e (patch) | |
tree | be3a3bec341ea19596ab580cd0a87c07ba0b27b9 /net/spdy | |
parent | d9fa43af8b1b234e3730d94d6850282f407d672f (diff) | |
download | chromium_src-073487ed936883ccd581b224c2c6cc6264abbf1e.zip chromium_src-073487ed936883ccd581b224c2c6cc6264abbf1e.tar.gz chromium_src-073487ed936883ccd581b224c2c6cc6264abbf1e.tar.bz2 |
SPDY - Support new status field in SPDY 3 GOAWAY.
Porting changes from server.
BUG=119221
R=rch
TEST=network unit tests
Review URL: https://chromiumcodereview.appspot.com/9814025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@128169 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/spdy')
-rw-r--r-- | net/spdy/buffered_spdy_framer.cc | 5 | ||||
-rw-r--r-- | net/spdy/buffered_spdy_framer.h | 3 | ||||
-rw-r--r-- | net/spdy/spdy_framer.cc | 41 | ||||
-rw-r--r-- | net/spdy/spdy_framer.h | 6 | ||||
-rw-r--r-- | net/spdy/spdy_framer_test.cc | 96 | ||||
-rw-r--r-- | net/spdy/spdy_protocol.h | 23 | ||||
-rw-r--r-- | net/spdy/spdy_protocol_test.cc | 8 | ||||
-rw-r--r-- | net/spdy/spdy_test_util_spdy2.cc | 2 | ||||
-rw-r--r-- | net/spdy/spdy_test_util_spdy3.cc | 2 |
9 files changed, 132 insertions, 54 deletions
diff --git a/net/spdy/buffered_spdy_framer.cc b/net/spdy/buffered_spdy_framer.cc index 909c27f..6a48a5d 100644 --- a/net/spdy/buffered_spdy_framer.cc +++ b/net/spdy/buffered_spdy_framer.cc @@ -204,8 +204,9 @@ SpdyPingControlFrame* BufferedSpdyFramer::CreatePingFrame( } SpdyGoAwayControlFrame* BufferedSpdyFramer::CreateGoAway( - SpdyStreamId last_accepted_stream_id) const { - return spdy_framer_.CreateGoAway(last_accepted_stream_id); + SpdyStreamId last_accepted_stream_id, + SpdyGoAwayStatus status) const { + return spdy_framer_.CreateGoAway(last_accepted_stream_id, status); } SpdyHeadersControlFrame* BufferedSpdyFramer::CreateHeaders( diff --git a/net/spdy/buffered_spdy_framer.h b/net/spdy/buffered_spdy_framer.h index 70859bf..f12421f 100644 --- a/net/spdy/buffered_spdy_framer.h +++ b/net/spdy/buffered_spdy_framer.h @@ -123,7 +123,8 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramer SpdySettingsControlFrame* CreateSettings(const SpdySettings& values) const; SpdyPingControlFrame* CreatePingFrame(uint32 unique_id) const; SpdyGoAwayControlFrame* CreateGoAway( - SpdyStreamId last_accepted_stream_id) const; + SpdyStreamId last_accepted_stream_id, + SpdyGoAwayStatus status) const; SpdyHeadersControlFrame* CreateHeaders(SpdyStreamId stream_id, SpdyControlFlags flags, bool compressed, diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc index 32415e1..3a41198 100644 --- a/net/spdy/spdy_framer.cc +++ b/net/spdy/spdy_framer.cc @@ -497,10 +497,16 @@ void SpdyFramer::ProcessControlFrameHeader() { } break; case GOAWAY: - if (current_control_frame.length() != - SpdyGoAwayControlFrame::size() - SpdyFrame::kHeaderSize) - set_error(SPDY_INVALID_CONTROL_FRAME); - break; + { + // SPDY 2 GOAWAY frames are 4 bytes smaller than in SPDY 3. We account + // for this difference via a separate offset variable, since + // SpdyGoAwayControlFrame::size() returns the SPDY 3 size. + const size_t goaway_offset = (protocol_version() < 3) ? 4 : 0; + if (current_control_frame.length() + goaway_offset != + SpdyGoAwayControlFrame::size() - SpdyFrame::kHeaderSize) + set_error(SPDY_INVALID_CONTROL_FRAME); + break; + } case HEADERS: if (current_control_frame.length() < SpdyHeadersControlFrame::size() - SpdyControlFrame::kHeaderSize) @@ -1176,15 +1182,24 @@ SpdyPingControlFrame* SpdyFramer::CreatePingFrame(uint32 unique_id) const { } SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway( - SpdyStreamId last_accepted_stream_id) const { + SpdyStreamId last_accepted_stream_id, + SpdyGoAwayStatus status) const { DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask); - SpdyFrameBuilder frame(SpdyGoAwayControlFrame::size()); + // SPDY 2 GOAWAY frames are 4 bytes smaller than in SPDY 3. We account for + // this difference via a separate offset variable, since + // SpdyGoAwayControlFrame::size() returns the SPDY 3 size. + const size_t goaway_offset = (protocol_version() < 3) ? 4 : 0; + SpdyFrameBuilder frame(SpdyGoAwayControlFrame::size() - goaway_offset); frame.WriteUInt16(kControlFlagMask | spdy_version_); frame.WriteUInt16(GOAWAY); - size_t go_away_size = SpdyGoAwayControlFrame::size() - SpdyFrame::kHeaderSize; + size_t go_away_size = + SpdyGoAwayControlFrame::size() - SpdyFrame::kHeaderSize - goaway_offset; frame.WriteUInt32(go_away_size); frame.WriteUInt32(last_accepted_stream_id); + if (protocol_version() >= 3) { + frame.WriteUInt32(status); + } return reinterpret_cast<SpdyGoAwayControlFrame*>(frame.take()); } @@ -1688,7 +1703,8 @@ SpdyFrame* SpdyFramer::DuplicateFrame(const SpdyFrame& frame) { return new_frame; } -size_t SpdyFramer::GetMinimumControlFrameSize(SpdyControlType type) { +size_t SpdyFramer::GetMinimumControlFrameSize(int version, + SpdyControlType type) { switch (type) { case SYN_STREAM: return SpdySynStreamControlFrame::size(); @@ -1706,7 +1722,14 @@ size_t SpdyFramer::GetMinimumControlFrameSize(SpdyControlType type) { case PING: return SpdyPingControlFrame::size(); case GOAWAY: - return SpdyGoAwayControlFrame::size(); + if (version < 3) { + // SPDY 2 GOAWAY is smaller by 32 bits. Since + // SpdyGoAwayControlFrame::size() returns the size for SPDY 3, we adjust + // before returning here. + return SpdyGoAwayControlFrame::size() - 4; + } else { + return SpdyGoAwayControlFrame::size(); + } case HEADERS: return SpdyHeadersControlFrame::size(); case WINDOW_UPDATE: diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h index 840c43b..d335a05 100644 --- a/net/spdy/spdy_framer.h +++ b/net/spdy/spdy_framer.h @@ -310,8 +310,8 @@ class NET_EXPORT_PRIVATE SpdyFramer { // prior to the shutting down of the TCP connection, and includes the // stream_id of the last stream the sender of the frame is willing to process // to completion. - SpdyGoAwayControlFrame* CreateGoAway( - SpdyStreamId last_accepted_stream_id) const; + SpdyGoAwayControlFrame* CreateGoAway(SpdyStreamId last_accepted_stream_id, + SpdyGoAwayStatus status) const; // Creates an instance of SpdyHeadersControlFrame. The HEADERS frame is used // for sending additional headers outside of a SYN_STREAM/SYN_REPLY. The @@ -382,7 +382,7 @@ class NET_EXPORT_PRIVATE SpdyFramer { // Get the minimum size of the control frame for the given control frame // type. This is useful for validating frame blocks. - static size_t GetMinimumControlFrameSize(SpdyControlType type); + static size_t GetMinimumControlFrameSize(int version, SpdyControlType type); // Get the stream ID for the given control frame (SYN_STREAM, SYN_REPLY, and // HEADERS). If the control frame is NULL or of another type, this diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc index a2f29bf..3c594ac 100644 --- a/net/spdy/spdy_framer_test.cc +++ b/net/spdy/spdy_framer_test.cc @@ -1926,26 +1926,47 @@ TEST_P(SpdyFramerTest, CreateGoAway) { { const char kDescription[] = "GOAWAY frame"; - const unsigned char kFrameData[] = { + const unsigned char kV2FrameData[] = { 0x80, spdy_version_, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, }; - scoped_ptr<SpdyGoAwayControlFrame> frame(framer.CreateGoAway(0)); - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + const unsigned char kV3FrameData[] = { + 0x80, spdy_version_, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + scoped_ptr<SpdyGoAwayControlFrame> frame(framer.CreateGoAway(0, GOAWAY_OK)); + CompareFrame(kDescription, + *frame, + IsSpdy2() ? kV2FrameData : kV3FrameData, + IsSpdy2() ? arraysize(kV2FrameData) + : arraysize(kV3FrameData)); EXPECT_EQ(SpdyFramer::kInvalidStream, SpdyFramer::GetControlFrameStreamId(frame.get())); } { - const char kDescription[] = "GOAWAY frame with max stream ID"; - const unsigned char kFrameData[] = { + const char kDescription[] = "GOAWAY frame with max stream ID, status"; + const unsigned char kV2FrameData[] = { 0x80, spdy_version_, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x7f, 0xff, 0xff, 0xff, }; - scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF)); - CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); + const unsigned char kV3FrameData[] = { + 0x80, spdy_version_, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x08, + 0x7f, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, + }; + scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF, + GOAWAY_INTERNAL_ERROR)); + CompareFrame(kDescription, + *frame, + IsSpdy2() ? kV2FrameData : kV3FrameData, + IsSpdy2() ? arraysize(kV2FrameData) + : arraysize(kV3FrameData)); } } @@ -2218,27 +2239,14 @@ TEST_P(SpdyFramerTest, ExpandBuffer_HeapSmash) { TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) { // Create a GoAway frame that has a few extra bytes at the end. - // We create enough overhead to require the framer to expand its frame buffer. + // We create enough overhead to overflow the framer's control frame buffer. size_t overhead = SpdyFramer::kUncompressedControlFrameBufferInitialSize; SpdyFramer framer(spdy_version_); - scoped_ptr<SpdyGoAwayControlFrame> goaway(framer.CreateGoAway(1)); + scoped_ptr<SpdyGoAwayControlFrame> goaway(framer.CreateGoAway(1, GOAWAY_OK)); goaway->set_length(goaway->length() + overhead); std::string pad('A', overhead); TestSpdyVisitor visitor(spdy_version_); - // First attempt without validation on. - visitor.framer_.set_validate_control_frame_sizes(false); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(goaway->data()), - goaway->length() - overhead + SpdyControlFrame::kHeaderSize); - visitor.SimulateInFramer( - reinterpret_cast<const unsigned char*>(pad.c_str()), - overhead); - EXPECT_EQ(0, visitor.error_count_); // Not an error. - EXPECT_EQ(1, visitor.goaway_count_); // The goaway was parsed. - - // Attempt with validation on. - visitor.framer_.set_validate_control_frame_sizes(true); visitor.SimulateInFramer( reinterpret_cast<unsigned char*>(goaway->data()), goaway->length() - overhead + SpdyControlFrame::kHeaderSize); @@ -2246,7 +2254,9 @@ TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) { reinterpret_cast<const unsigned char*>(pad.c_str()), overhead); EXPECT_EQ(1, visitor.error_count_); // This generated an error. - EXPECT_EQ(1, visitor.goaway_count_); // Unchanged from before. + EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, + visitor.framer_.error_code()); + EXPECT_EQ(0, visitor.goaway_count_); // Frame not parsed. } TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) { @@ -2566,27 +2576,43 @@ TEST_P(SpdyFramerTest, ControlTypeToStringTest) { TEST_P(SpdyFramerTest, GetMinimumControlFrameSizeTest) { EXPECT_EQ(SpdySynStreamControlFrame::size(), - SpdyFramer::GetMinimumControlFrameSize(SYN_STREAM)); + SpdyFramer::GetMinimumControlFrameSize(spdy_version_, + SYN_STREAM)); EXPECT_EQ(SpdySynReplyControlFrame::size(), - SpdyFramer::GetMinimumControlFrameSize(SYN_REPLY)); + SpdyFramer::GetMinimumControlFrameSize(spdy_version_, + SYN_REPLY)); EXPECT_EQ(SpdyRstStreamControlFrame::size(), - SpdyFramer::GetMinimumControlFrameSize(RST_STREAM)); + SpdyFramer::GetMinimumControlFrameSize(spdy_version_, + RST_STREAM)); EXPECT_EQ(SpdySettingsControlFrame::size(), - SpdyFramer::GetMinimumControlFrameSize(SETTINGS)); + SpdyFramer::GetMinimumControlFrameSize(spdy_version_, + SETTINGS)); EXPECT_EQ(SpdyFrame::kHeaderSize, - SpdyFramer::GetMinimumControlFrameSize(NOOP)); + SpdyFramer::GetMinimumControlFrameSize(spdy_version_, + NOOP)); EXPECT_EQ(SpdyPingControlFrame::size(), - SpdyFramer::GetMinimumControlFrameSize(PING)); - EXPECT_EQ(SpdyGoAwayControlFrame::size(), - SpdyFramer::GetMinimumControlFrameSize(GOAWAY)); + SpdyFramer::GetMinimumControlFrameSize(spdy_version_, + PING)); + size_t goaway_size = SpdyGoAwayControlFrame::size(); + if (IsSpdy2()) { + // SPDY 2 GOAWAY is smaller by 32 bits. + goaway_size -= 4; + } + EXPECT_EQ(goaway_size, + SpdyFramer::GetMinimumControlFrameSize(spdy_version_, + GOAWAY)); EXPECT_EQ(SpdyHeadersControlFrame::size(), - SpdyFramer::GetMinimumControlFrameSize(HEADERS)); + SpdyFramer::GetMinimumControlFrameSize(spdy_version_, + HEADERS)); EXPECT_EQ(SpdyWindowUpdateControlFrame::size(), - SpdyFramer::GetMinimumControlFrameSize(WINDOW_UPDATE)); + SpdyFramer::GetMinimumControlFrameSize(spdy_version_, + WINDOW_UPDATE)); EXPECT_EQ(SpdyCredentialControlFrame::size(), - SpdyFramer::GetMinimumControlFrameSize(CREDENTIAL)); + SpdyFramer::GetMinimumControlFrameSize(spdy_version_, + CREDENTIAL)); EXPECT_EQ(static_cast<size_t>(0x7FFFFFFF), - SpdyFramer::GetMinimumControlFrameSize(NUM_CONTROL_FRAME_TYPES)); + SpdyFramer::GetMinimumControlFrameSize(spdy_version_, + NUM_CONTROL_FRAME_TYPES)); } TEST_P(SpdyFramerTest, CatchProbableHttpResponse) { diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h index cb09456..c6649f7 100644 --- a/net/spdy/spdy_protocol.h +++ b/net/spdy/spdy_protocol.h @@ -434,6 +434,14 @@ enum SpdyStatusCodes { NUM_STATUS_CODES = 9 }; +enum SpdyGoAwayStatus { + GOAWAY_INVALID = -1, + GOAWAY_OK = 0, + GOAWAY_PROTOCOL_ERROR = 1, + GOAWAY_INTERNAL_ERROR = 2, + GOAWAY_NUM_STATUS_CODES = 3 +}; + // A SPDY stream id is a 31 bit entity. typedef uint32 SpdyStreamId; @@ -517,6 +525,7 @@ struct SpdyCredentialControlFrameBlock : SpdyFrameBlock { // A GOAWAY Control Frame structure. struct SpdyGoAwayControlFrameBlock : SpdyFrameBlock { SpdyStreamId last_accepted_stream_id_; + SpdyGoAwayStatus status_; }; // A HEADERS Control Frame structure. @@ -923,6 +932,20 @@ class SpdyGoAwayControlFrame : public SpdyControlFrame { return ntohl(block()->last_accepted_stream_id_) & kStreamIdMask; } + SpdyGoAwayStatus status() const { + if (version() < 2) { + LOG(DFATAL) << "Attempted to access status of SPDY 2 GOAWAY."; + return GOAWAY_INVALID; + } else { + uint32 status = ntohl(block()->status_); + if (status >= GOAWAY_NUM_STATUS_CODES) { + return GOAWAY_INVALID; + } else { + return static_cast<SpdyGoAwayStatus>(status); + } + } + } + void set_last_accepted_stream_id(SpdyStreamId id) { mutable_block()->last_accepted_stream_id_ = htonl(id & kStreamIdMask); } diff --git a/net/spdy/spdy_protocol_test.cc b/net/spdy/spdy_protocol_test.cc index b327bc1..c739c90 100644 --- a/net/spdy/spdy_protocol_test.cc +++ b/net/spdy/spdy_protocol_test.cc @@ -13,6 +13,7 @@ using spdy::CONTROL_FLAG_FIN; using spdy::CONTROL_FLAG_NONE; using spdy::FlagsAndLength; using spdy::GOAWAY; +using spdy::GOAWAY_INTERNAL_ERROR; using spdy::HEADERS; using spdy::NOOP; using spdy::NUM_CONTROL_FRAME_TYPES; @@ -80,7 +81,7 @@ TEST_P(SpdyProtocolTest, ProtocolConstants) { EXPECT_EQ(16u, SpdyRstStreamControlFrame::size()); EXPECT_EQ(12u, SpdySettingsControlFrame::size()); EXPECT_EQ(12u, SpdyPingControlFrame::size()); - EXPECT_EQ(12u, SpdyGoAwayControlFrame::size()); + EXPECT_EQ(16u, SpdyGoAwayControlFrame::size()); EXPECT_EQ(12u, SpdyHeadersControlFrame::size()); EXPECT_EQ(16u, SpdyWindowUpdateControlFrame::size()); EXPECT_EQ(4u, sizeof(FlagsAndLength)); @@ -167,11 +168,14 @@ TEST_P(SpdyProtocolTest, ControlFrameStructs) { EXPECT_EQ(kUniqueId2, ping_frame->unique_id()); scoped_ptr<SpdyGoAwayControlFrame> goaway_frame( - framer.CreateGoAway(123)); + framer.CreateGoAway(123, GOAWAY_INTERNAL_ERROR)); EXPECT_EQ(framer.protocol_version(), goaway_frame->version()); EXPECT_TRUE(goaway_frame->is_control_frame()); EXPECT_EQ(GOAWAY, goaway_frame->type()); EXPECT_EQ(123u, goaway_frame->last_accepted_stream_id()); + if (!IsSpdy2()) { + EXPECT_EQ(GOAWAY_INTERNAL_ERROR, goaway_frame->status()); + } scoped_ptr<SpdyHeadersControlFrame> headers_frame( framer.CreateHeaders(123, CONTROL_FLAG_NONE, false, &headers)); diff --git a/net/spdy/spdy_test_util_spdy2.cc b/net/spdy/spdy_test_util_spdy2.cc index 1f82401..1f6dbfd 100644 --- a/net/spdy/spdy_test_util_spdy2.cc +++ b/net/spdy/spdy_test_util_spdy2.cc @@ -220,7 +220,7 @@ spdy::SpdyFrame* ConstructSpdyPing() { // Returns the constructed frame. The caller takes ownership of the frame. spdy::SpdyFrame* ConstructSpdyGoAway() { spdy::BufferedSpdyFramer framer(2); - return framer.CreateGoAway(0); + return framer.CreateGoAway(0, spdy::GOAWAY_OK); } // Construct a SPDY WINDOW_UPDATE frame. diff --git a/net/spdy/spdy_test_util_spdy3.cc b/net/spdy/spdy_test_util_spdy3.cc index 67ec3eb..9bd8bd5 100644 --- a/net/spdy/spdy_test_util_spdy3.cc +++ b/net/spdy/spdy_test_util_spdy3.cc @@ -220,7 +220,7 @@ spdy::SpdyFrame* ConstructSpdyPing() { // Returns the constructed frame. The caller takes ownership of the frame. spdy::SpdyFrame* ConstructSpdyGoAway() { spdy::BufferedSpdyFramer framer(3); - return framer.CreateGoAway(0); + return framer.CreateGoAway(0, spdy::GOAWAY_OK); } // Construct a SPDY WINDOW_UPDATE frame. |