summaryrefslogtreecommitdiffstats
path: root/net/spdy
diff options
context:
space:
mode:
authorrtenneti@google.com <rtenneti@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-22 04:11:22 +0000
committerrtenneti@google.com <rtenneti@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-22 04:11:22 +0000
commit073487ed936883ccd581b224c2c6cc6264abbf1e (patch)
treebe3a3bec341ea19596ab580cd0a87c07ba0b27b9 /net/spdy
parentd9fa43af8b1b234e3730d94d6850282f407d672f (diff)
downloadchromium_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.cc5
-rw-r--r--net/spdy/buffered_spdy_framer.h3
-rw-r--r--net/spdy/spdy_framer.cc41
-rw-r--r--net/spdy/spdy_framer.h6
-rw-r--r--net/spdy/spdy_framer_test.cc96
-rw-r--r--net/spdy/spdy_protocol.h23
-rw-r--r--net/spdy/spdy_protocol_test.cc8
-rw-r--r--net/spdy/spdy_test_util_spdy2.cc2
-rw-r--r--net/spdy/spdy_test_util_spdy3.cc2
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.