summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-02 01:51:01 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-02 01:51:01 +0000
commit96f0e9e2b49168ef28539e7381780891a8cc9c09 (patch)
treea3958547e7eb385d208619c46afdb057bfebaddc
parent2224d50902cc923cc0fe2dcaf23916984f1942e7 (diff)
downloadchromium_src-96f0e9e2b49168ef28539e7381780891a8cc9c09.zip
chromium_src-96f0e9e2b49168ef28539e7381780891a8cc9c09.tar.gz
chromium_src-96f0e9e2b49168ef28539e7381780891a8cc9c09.tar.bz2
Support SPDY 4 common header framing.
This lands server change 43180125. Also add comments regarding the maximum frame size. Also update test data for compressed frames. Review URL: https://chromiumcodereview.appspot.com/12378031 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@185653 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/spdy/spdy_frame_builder.cc74
-rw-r--r--net/spdy/spdy_frame_builder_test.cc3
-rw-r--r--net/spdy/spdy_framer.cc272
-rw-r--r--net/spdy/spdy_framer.h23
-rw-r--r--net/spdy/spdy_framer_test.cc1041
-rw-r--r--net/spdy/spdy_test_utils.cc12
6 files changed, 1069 insertions, 356 deletions
diff --git a/net/spdy/spdy_frame_builder.cc b/net/spdy/spdy_frame_builder.cc
index 957e777..64ecc30 100644
--- a/net/spdy/spdy_frame_builder.cc
+++ b/net/spdy/spdy_frame_builder.cc
@@ -60,11 +60,19 @@ bool SpdyFrameBuilder::Seek(size_t length) {
bool SpdyFrameBuilder::WriteControlFrameHeader(const SpdyFramer& framer,
SpdyControlType type,
uint8 flags) {
- FlagsAndLength flags_length = CreateFlagsAndLength(
- flags, capacity_ - framer.GetControlFrameHeaderSize());
- bool success = WriteUInt16(kControlFlagMask | framer.protocol_version());
- success &= WriteUInt16(type);
- success &= WriteBytes(&flags_length, sizeof(flags_length));
+ bool success = true;
+ if (framer.protocol_version() < 4) {
+ FlagsAndLength flags_length = CreateFlagsAndLength(
+ flags, capacity_ - framer.GetControlFrameHeaderSize());
+ success &= WriteUInt16(kControlFlagMask | framer.protocol_version());
+ success &= WriteUInt16(type);
+ success &= WriteBytes(&flags_length, sizeof(flags_length));
+ } else {
+ DCHECK_GT(1u<<16, capacity_); // Make sure length fits in 2B.
+ success &= WriteUInt16(capacity_);
+ success &= WriteUInt8(type);
+ success &= WriteUInt8(flags);
+ }
DCHECK_EQ(framer.GetControlFrameHeaderSize(), length());
return success;
}
@@ -73,14 +81,23 @@ bool SpdyFrameBuilder::WriteDataFrameHeader(const SpdyFramer& framer,
SpdyStreamId stream_id,
SpdyDataFlags flags) {
DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
- bool success = WriteUInt32(stream_id);
- size_t length_field = capacity_ - framer.GetDataFrameMinimumSize();
- DCHECK_EQ(0u, length_field & ~static_cast<size_t>(kLengthMask));
- FlagsAndLength flags_length;
- flags_length.length_ = htonl(length_field);
- DCHECK_EQ(0, flags & ~kDataFlagsMask);
- flags_length.flags_[0] = flags;
- success &= WriteBytes(&flags_length, sizeof(flags_length));
+ bool success = true;
+ if (framer.protocol_version() < 4) {
+ success &= WriteUInt32(stream_id);
+ size_t length_field = capacity_ - framer.GetDataFrameMinimumSize();
+ DCHECK_EQ(0u, length_field & ~static_cast<size_t>(kLengthMask));
+ FlagsAndLength flags_length;
+ flags_length.length_ = htonl(length_field);
+ DCHECK_EQ(0, flags & ~kDataFlagsMask);
+ flags_length.flags_[0] = flags;
+ success &= WriteBytes(&flags_length, sizeof(flags_length));
+ } else {
+ DCHECK_GT(1u<<16, capacity_); // Make sure length fits in 2B.
+ success &= WriteUInt16(capacity_);
+ success &= WriteUInt8(0);
+ success &= WriteUInt8(flags);
+ success &= WriteUInt32(stream_id);
+ }
DCHECK_EQ(framer.GetDataFrameMinimumSize(), length());
return success;
}
@@ -117,20 +134,33 @@ bool SpdyFrameBuilder::WriteBytes(const void* data, uint32 data_len) {
}
bool SpdyFrameBuilder::RewriteLength(const SpdyFramer& framer) {
- return OverwriteLength(framer, length_ - framer.GetControlFrameHeaderSize());
+ if (framer.protocol_version() < 4) {
+ return OverwriteLength(framer,
+ length_ - framer.GetControlFrameHeaderSize());
+ } else {
+ return OverwriteLength(framer, length_);
+ }
}
bool SpdyFrameBuilder::OverwriteLength(const SpdyFramer& framer,
size_t length) {
- FlagsAndLength flags_length = CreateFlagsAndLength(
- 0, // We're not writing over the flags value anyway.
- length);
-
- // Write into the correct location by temporarily faking the offset.
+ bool success = false;
const size_t old_length = length_;
- length_ = 5; // Offset at which the length field occurs.
- bool success = WriteBytes(reinterpret_cast<char*>(&flags_length) + 1,
- sizeof(flags_length) - 1);
+
+ if (framer.protocol_version() < 4) {
+ FlagsAndLength flags_length = CreateFlagsAndLength(
+ 0, // We're not writing over the flags value anyway.
+ length);
+
+ // Write into the correct location by temporarily faking the offset.
+ length_ = 5; // Offset at which the length field occurs.
+ success = WriteBytes(reinterpret_cast<char*>(&flags_length) + 1,
+ sizeof(flags_length) - 1);
+ } else {
+ length_ = 0;
+ success = WriteUInt16(length);
+ }
+
length_ = old_length;
return success;
}
diff --git a/net/spdy/spdy_frame_builder_test.cc b/net/spdy/spdy_frame_builder_test.cc
index d14f697..eeea2b6 100644
--- a/net/spdy/spdy_frame_builder_test.cc
+++ b/net/spdy/spdy_frame_builder_test.cc
@@ -26,6 +26,7 @@ TEST(SpdyFrameBuilderTestVersionAgnostic, GetWritableBuffer) {
enum SpdyFrameBuilderTestTypes {
SPDY2 = 2,
SPDY3 = 3,
+ SPDY4 = 4,
};
class SpdyFrameBuilderTest
@@ -42,7 +43,7 @@ class SpdyFrameBuilderTest
// All tests are run with two different SPDY versions: SPDY/2 and SPDY/3.
INSTANTIATE_TEST_CASE_P(SpdyFrameBuilderTests,
SpdyFrameBuilderTest,
- ::testing::Values(SPDY2, SPDY3));
+ ::testing::Values(SPDY2, SPDY3, SPDY4));
TEST_P(SpdyFrameBuilderTest, RewriteLength) {
// Create an empty SETTINGS frame both via framer and manually via builder.
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index 7d4fd2c..1d83d32 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -52,7 +52,7 @@ const uint8 kNoFlags = 0;
} // namespace
const int SpdyFramer::kMinSpdyVersion = 2;
-const int SpdyFramer::kMaxSpdyVersion = 3;
+const int SpdyFramer::kMaxSpdyVersion = 4;
const SpdyStreamId SpdyFramer::kInvalidStream = -1;
const size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024;
// The size of the control frame buffer. Must be >= the minimum size of the
@@ -143,8 +143,7 @@ void SpdyFramer::Reset() {
state_ = SPDY_RESET;
previous_state_ = SPDY_RESET;
error_code_ = SPDY_NO_ERROR;
- remaining_data_ = 0;
- remaining_control_payload_ = 0;
+ remaining_data_length_ = 0;
remaining_control_header_ = 0;
current_frame_buffer_length_ = 0;
current_frame_type_ = NUM_CONTROL_FRAME_TYPES;
@@ -161,11 +160,17 @@ size_t SpdyFramer::GetDataFrameMinimumSize() const {
return 8;
}
+// Size, in bytes, of the control frame header.
size_t SpdyFramer::GetControlFrameHeaderSize() const {
- // Size, in bytes, of the control frame header. Future versions of SPDY
- // will likely vary this, so we allow for the flexibility of a function call
- // for this value as opposed to a constant.
- return 8;
+ switch (protocol_version()) {
+ case 2:
+ case 3:
+ return 8;
+ case 4:
+ return 4;
+ }
+ LOG(DFATAL) << "Unhandled SPDY version.";
+ return 0;
}
size_t SpdyFramer::GetSynStreamMinimumSize() const {
@@ -459,8 +464,7 @@ size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
bottom:
DCHECK(len == 0 || state_ == SPDY_ERROR);
if (current_frame_buffer_length_ == 0 &&
- remaining_data_ == 0 &&
- remaining_control_payload_ == 0 &&
+ remaining_data_length_ == 0 &&
remaining_control_header_ == 0) {
DCHECK(state_ == SPDY_RESET || state_ == SPDY_ERROR)
<< "State: " << StateToString(state_);
@@ -484,80 +488,133 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
}
if (current_frame_buffer_length_ < GetControlFrameHeaderSize()) {
- // TODO(rch): remove this empty block
- // Do nothing.
- } else {
- SpdyFrameReader reader(current_frame_buffer_.get(),
- current_frame_buffer_length_);
+ // Not enough information to do anything meaningful.
+ return original_len - len;
+ }
+
+ // Using a scoped_ptr here since we may need to create a new SpdyFrameReader
+ // when processing DATA frames below.
+ scoped_ptr<SpdyFrameReader> reader(
+ new SpdyFrameReader(current_frame_buffer_.get(),
+ current_frame_buffer_length_));
- uint16 version = 0;
- bool successful_read = reader.ReadUInt16(&version);
+ uint16 version = 0;
+ bool is_control_frame = false;
+
+ if (protocol_version() < 4) {
+ bool successful_read = reader->ReadUInt16(&version);
DCHECK(successful_read);
- bool control_bit = (version & kControlFlagMask) != 0;
+ is_control_frame = (version & kControlFlagMask) != 0;
version &= ~kControlFlagMask; // Only valid for control frames.
- if (control_bit) {
+ if (is_control_frame) {
uint16 frame_type_field;
- successful_read = reader.ReadUInt16(&frame_type_field);
+ successful_read = reader->ReadUInt16(&frame_type_field);
// We check for validity below in ProcessControlFrameHeader().
current_frame_type_ = static_cast<SpdyControlType>(frame_type_field);
} else {
- reader.Rewind();
- successful_read = reader.ReadUInt31(&current_frame_stream_id_);
+ reader->Rewind();
+ successful_read = reader->ReadUInt31(&current_frame_stream_id_);
}
DCHECK(successful_read);
- successful_read = reader.ReadUInt8(&current_frame_flags_);
+ successful_read = reader->ReadUInt8(&current_frame_flags_);
DCHECK(successful_read);
- successful_read = reader.ReadUInt24(&current_frame_length_);
+ uint32 length_field = 0;
+ successful_read = reader->ReadUInt24(&length_field);
DCHECK(successful_read);
- remaining_data_ = current_frame_length_;
-
- // This is just a sanity check for help debugging early frame errors.
- if (remaining_data_ > 1000000u) {
- // The strncmp for 5 is safe because we only hit this point if we
- // have GetControlFrameHeaderSize() (8) bytes
- if (!syn_frame_processed_ &&
- strncmp(current_frame_buffer_.get(), "HTTP/", 5) == 0) {
- LOG(WARNING) << "Unexpected HTTP response to " << display_protocol_
- << " request";
- probable_http_response_ = true;
- } else {
- LOG(WARNING) << "Unexpectedly large frame. " << display_protocol_
- << " session is likely corrupt.";
+ remaining_data_length_ = length_field;
+ current_frame_length_ = remaining_data_length_ + reader->GetBytesConsumed();
+ } else {
+ // TODO(hkhalil): Avoid re-reading fields as possible for DATA frames?
+ version = protocol_version();
+ uint16 length_field = 0;
+ bool successful_read = reader->ReadUInt16(&length_field);
+ DCHECK(successful_read);
+ current_frame_length_ = length_field;
+
+ uint8 frame_type_field = 0;
+ successful_read = reader->ReadUInt8(&frame_type_field);
+ DCHECK(successful_read);
+ if (frame_type_field != 0) {
+ is_control_frame = true;
+ // We check for validity below in ProcessControlFrameHeader().
+ current_frame_type_ = static_cast<SpdyControlType>(frame_type_field);
+ }
+
+ successful_read = reader->ReadUInt8(&current_frame_flags_);
+ DCHECK(successful_read);
+
+ if (!is_control_frame) {
+ // We may not have the entirety of the DATA frame header.
+ if (current_frame_buffer_length_ < GetDataFrameMinimumSize()) {
+ size_t bytes_desired =
+ GetDataFrameMinimumSize() - current_frame_buffer_length_;
+ UpdateCurrentFrameBuffer(&data, &len, bytes_desired);
+ if (current_frame_buffer_length_ < GetDataFrameMinimumSize()) {
+ return original_len - len;
+ }
}
+ // Construct a new SpdyFrameReader aware of the new frame length.
+ reader.reset(new SpdyFrameReader(current_frame_buffer_.get(),
+ current_frame_buffer_length_));
+ reader->Seek(GetControlFrameHeaderSize());
+ successful_read = reader->ReadUInt31(&current_frame_stream_id_);
+ DCHECK(successful_read);
}
+ remaining_data_length_ = current_frame_length_ - reader->GetBytesConsumed();
+ }
+ DCHECK_EQ(is_control_frame ? GetControlFrameHeaderSize()
+ : GetDataFrameMinimumSize(),
+ reader->GetBytesConsumed());
+ DCHECK_EQ(current_frame_length_,
+ remaining_data_length_ + reader->GetBytesConsumed());
+
+ // This is just a sanity check for help debugging early frame errors.
+ if (remaining_data_length_ > 1000000u) {
+ // The strncmp for 5 is safe because we only hit this point if we
+ // have kMinCommonHeader (8) bytes
+ if (!syn_frame_processed_ &&
+ strncmp(current_frame_buffer_.get(), "HTTP/", 5) == 0) {
+ LOG(WARNING) << "Unexpected HTTP response to " << display_protocol_
+ << " request";
+ probable_http_response_ = true;
+ } else {
+ LOG(WARNING) << "Unexpectedly large frame. " << display_protocol_
+ << " session is likely corrupt.";
+ }
+ }
- // if we're here, then we have the common header all received.
- if (!control_bit) {
- if (current_frame_flags_ & ~DATA_FLAG_FIN) {
- set_error(SPDY_INVALID_DATA_FRAME_FLAGS);
+ // if we're here, then we have the common header all received.
+ if (!is_control_frame) {
+ if (current_frame_flags_ & ~DATA_FLAG_FIN) {
+ set_error(SPDY_INVALID_DATA_FRAME_FLAGS);
+ } else {
+ visitor_->OnDataFrameHeader(current_frame_stream_id_,
+ remaining_data_length_,
+ current_frame_flags_ & DATA_FLAG_FIN);
+ if (remaining_data_length_ > 0) {
+ CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
} else {
- visitor_->OnDataFrameHeader(current_frame_stream_id_,
- current_frame_length_,
- current_frame_flags_ & DATA_FLAG_FIN);
- if (current_frame_length_ > 0) {
- CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
- } else {
- // Empty data frame.
- if (current_frame_flags_ & DATA_FLAG_FIN) {
- visitor_->OnStreamFrameData(current_frame_stream_id_,
- NULL, 0, DATA_FLAG_FIN);
- }
- CHANGE_STATE(SPDY_AUTO_RESET);
+ // Empty data frame.
+ if (current_frame_flags_ & DATA_FLAG_FIN) {
+ visitor_->OnStreamFrameData(current_frame_stream_id_,
+ NULL, 0, DATA_FLAG_FIN);
}
+ CHANGE_STATE(SPDY_AUTO_RESET);
}
- } else if (version != spdy_version_) {
- // We check version before we check validity: version can never be
- // 'invalid', it can only be unsupported.
- DLOG(INFO) << "Unsupported SPDY version " << version
- << " (expected " << spdy_version_ << ")";
- set_error(SPDY_UNSUPPORTED_VERSION);
- } else {
- ProcessControlFrameHeader();
}
+ } else if (version != spdy_version_) {
+ // We check version before we check validity: version can never be
+ // 'invalid', it can only be unsupported.
+ DLOG(INFO) << "Unsupported SPDY version " << version
+ << " (expected " << spdy_version_ << ")";
+ set_error(SPDY_UNSUPPORTED_VERSION);
+ } else {
+ ProcessControlFrameHeader();
}
+
return original_len - len;
}
@@ -581,8 +638,7 @@ void SpdyFramer::ProcessControlFrameHeader() {
// Do some sanity checking on the control frame sizes and flags.
switch (current_frame_type_) {
case SYN_STREAM:
- if (current_frame_length_ <
- GetSynStreamMinimumSize() - GetControlFrameHeaderSize()) {
+ if (current_frame_length_ < GetSynStreamMinimumSize()) {
set_error(SPDY_INVALID_CONTROL_FRAME);
} else if (current_frame_flags_ &
~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
@@ -590,16 +646,14 @@ void SpdyFramer::ProcessControlFrameHeader() {
}
break;
case SYN_REPLY:
- if (current_frame_length_ <
- GetSynReplyMinimumSize() - GetControlFrameHeaderSize()) {
+ if (current_frame_length_ < GetSynReplyMinimumSize()) {
set_error(SPDY_INVALID_CONTROL_FRAME);
} else if (current_frame_flags_ & ~CONTROL_FLAG_FIN) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
}
break;
case RST_STREAM:
- if (current_frame_length_ !=
- GetRstStreamSize() - GetControlFrameHeaderSize()) {
+ if (current_frame_length_ != GetRstStreamSize()) {
set_error(SPDY_INVALID_CONTROL_FRAME);
} else if (current_frame_flags_ != 0) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
@@ -608,9 +662,8 @@ void SpdyFramer::ProcessControlFrameHeader() {
case SETTINGS:
// Make sure that we have an integral number of 8-byte key/value pairs,
// plus a 4-byte length field.
- if (current_frame_length_ <
- GetSettingsMinimumSize() - GetControlFrameHeaderSize() ||
- current_frame_length_ % 8 != 4) {
+ if (current_frame_length_ < GetSettingsMinimumSize() ||
+ (current_frame_length_ - GetControlFrameHeaderSize()) % 8 != 4) {
DLOG(WARNING) << "Invalid length for SETTINGS frame: "
<< current_frame_length_;
set_error(SPDY_INVALID_CONTROL_FRAME);
@@ -621,8 +674,7 @@ void SpdyFramer::ProcessControlFrameHeader() {
break;
case GOAWAY:
{
- if (current_frame_length_ !=
- GetGoAwaySize() - GetControlFrameHeaderSize()) {
+ if (current_frame_length_ != GetGoAwaySize()) {
set_error(SPDY_INVALID_CONTROL_FRAME);
} else if (current_frame_flags_ != 0) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
@@ -630,32 +682,28 @@ void SpdyFramer::ProcessControlFrameHeader() {
break;
}
case HEADERS:
- if (current_frame_length_ <
- GetHeadersMinimumSize() - GetControlFrameHeaderSize()) {
+ if (current_frame_length_ < GetHeadersMinimumSize()) {
set_error(SPDY_INVALID_CONTROL_FRAME);
} else if (current_frame_flags_ & ~CONTROL_FLAG_FIN) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
}
break;
case WINDOW_UPDATE:
- if (current_frame_length_ !=
- GetWindowUpdateSize() - GetControlFrameHeaderSize()) {
+ if (current_frame_length_ != GetWindowUpdateSize()) {
set_error(SPDY_INVALID_CONTROL_FRAME);
} else if (current_frame_flags_ != 0) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
}
break;
case PING:
- if (current_frame_length_ !=
- GetPingSize() - GetControlFrameHeaderSize()) {
+ if (current_frame_length_ != GetPingSize()) {
set_error(SPDY_INVALID_CONTROL_FRAME);
} else if (current_frame_flags_ != 0) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
}
break;
case CREDENTIAL:
- if (current_frame_length_ <
- GetCredentialMinimumSize() - GetControlFrameHeaderSize()) {
+ if (current_frame_length_ < GetCredentialMinimumSize()) {
set_error(SPDY_INVALID_CONTROL_FRAME);
} else if (current_frame_flags_ != 0) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
@@ -678,12 +726,9 @@ void SpdyFramer::ProcessControlFrameHeader() {
return;
}
- remaining_control_payload_ = current_frame_length_;
- const size_t total_frame_size =
- remaining_control_payload_ + GetControlFrameHeaderSize();
- if (total_frame_size > GetControlFrameBufferMaxSize()) {
+ if (current_frame_length_ > GetControlFrameBufferMaxSize()) {
DLOG(WARNING) << "Received control frame with way too big of a payload: "
- << total_frame_size;
+ << current_frame_length_;
set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
return;
}
@@ -716,7 +761,7 @@ void SpdyFramer::ProcessControlFrameHeader() {
}
if ((frame_size_without_variable_data == -1) &&
- (total_frame_size > kControlFrameBufferSize)) {
+ (current_frame_length_ > kControlFrameBufferSize)) {
// We should already be in an error state. Double-check.
DCHECK_EQ(SPDY_ERROR, state_);
if (state_ != SPDY_ERROR) {
@@ -726,6 +771,7 @@ void SpdyFramer::ProcessControlFrameHeader() {
}
return;
}
+
if (frame_size_without_variable_data > 0) {
// We have a control frame with a header block. We need to parse the
// remainder of the control frame's header before we can parse the header
@@ -734,8 +780,6 @@ void SpdyFramer::ProcessControlFrameHeader() {
static_cast<int32>(current_frame_buffer_length_));
remaining_control_header_ = frame_size_without_variable_data -
current_frame_buffer_length_;
- remaining_control_payload_ += GetControlFrameHeaderSize() -
- frame_size_without_variable_data;
CHANGE_STATE(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK);
return;
}
@@ -972,6 +1016,7 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
remaining_control_header_);
remaining_control_header_ -= bytes_read;
+ remaining_data_length_ -= bytes_read;
}
if (remaining_control_header_ == 0) {
@@ -1065,7 +1110,7 @@ size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
current_frame_type_ != HEADERS) {
LOG(DFATAL) << "Unhandled frame type in ProcessControlFrameHeaderBlock.";
}
- size_t process_bytes = std::min(data_len, remaining_control_payload_);
+ size_t process_bytes = std::min(data_len, remaining_data_length_);
if (process_bytes > 0) {
if (enable_compression_) {
processed_successfully = IncrementallyDecompressControlFrameHeaderData(
@@ -1075,12 +1120,11 @@ size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
current_frame_stream_id_, data, process_bytes);
}
- remaining_control_payload_ -= process_bytes;
- remaining_data_ -= process_bytes;
+ remaining_data_length_ -= process_bytes;
}
// Handle the case that there is no futher data in this frame.
- if (remaining_control_payload_ == 0 && processed_successfully) {
+ if (remaining_data_length_ == 0 && processed_successfully) {
// The complete header block has been delivered. We send a zero-length
// OnControlFrameHeaderData() to indicate this.
visitor_->OnControlFrameHeaderData(current_frame_stream_id_, NULL, 0);
@@ -1107,7 +1151,7 @@ size_t SpdyFramer::ProcessSettingsFramePayload(const char* data,
size_t data_len) {
DCHECK_EQ(SPDY_SETTINGS_FRAME_PAYLOAD, state_);
DCHECK_EQ(SETTINGS, current_frame_type_);
- size_t unprocessed_bytes = std::min(data_len, remaining_control_payload_);
+ size_t unprocessed_bytes = std::min(data_len, remaining_data_length_);
size_t processed_bytes = 0;
// Loop over our incoming data.
@@ -1148,8 +1192,8 @@ size_t SpdyFramer::ProcessSettingsFramePayload(const char* data,
}
// Check if we're done handling this SETTINGS frame.
- remaining_control_payload_ -= processed_bytes;
- if (remaining_control_payload_ == 0) {
+ remaining_data_length_ -= processed_bytes;
+ if (remaining_data_length_ == 0) {
CHANGE_STATE(SPDY_AUTO_RESET);
}
@@ -1207,12 +1251,11 @@ bool SpdyFramer::ProcessSetting(const char* data) {
size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) {
size_t original_len = len;
- if (remaining_control_payload_) {
- size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
- remaining_control_payload_);
- remaining_control_payload_ -= bytes_read;
- remaining_data_ -= bytes_read;
- if (remaining_control_payload_ == 0) {
+ if (remaining_data_length_) {
+ size_t bytes_read =
+ UpdateCurrentFrameBuffer(&data, &len, remaining_data_length_);
+ remaining_data_length_ -= bytes_read;
+ if (remaining_data_length_ == 0) {
SpdyFrameReader reader(current_frame_buffer_.get(),
current_frame_buffer_length_);
reader.Seek(GetControlFrameHeaderSize()); // Skip frame header.
@@ -1234,8 +1277,8 @@ size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) {
successful_read = reader.ReadUInt31(&delta_window_size);
DCHECK(successful_read);
DCHECK(reader.IsDoneReading());
- visitor_->OnWindowUpdate(
- current_frame_stream_id_, delta_window_size);
+ visitor_->OnWindowUpdate(current_frame_stream_id_,
+ delta_window_size);
}
break;
case RST_STREAM: {
@@ -1291,14 +1334,11 @@ size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) {
size_t SpdyFramer::ProcessCredentialFramePayload(const char* data, size_t len) {
if (len > 0) {
- // Process only up to the end of this CREDENTIAL frame.
- len = std::min(len, remaining_control_payload_);
bool processed_succesfully = visitor_->OnCredentialFrameData(data, len);
- remaining_control_payload_ -= len;
- remaining_data_ -= len;
+ remaining_data_length_ -= len;
if (!processed_succesfully) {
set_error(SPDY_CREDENTIAL_FRAME_CORRUPT);
- } else if (remaining_control_payload_ == 0) {
+ } else if (remaining_data_length_ == 0) {
visitor_->OnCredentialFrameData(NULL, 0);
CHANGE_STATE(SPDY_AUTO_RESET);
}
@@ -1309,8 +1349,8 @@ size_t SpdyFramer::ProcessCredentialFramePayload(const char* data, size_t len) {
size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
size_t original_len = len;
- if (remaining_data_ > 0) {
- size_t amount_to_forward = std::min(remaining_data_, len);
+ if (remaining_data_length_ > 0) {
+ size_t amount_to_forward = std::min(remaining_data_length_, len);
if (amount_to_forward && state_ != SPDY_IGNORE_REMAINING_PAYLOAD) {
// Only inform the visitor if there is data.
if (amount_to_forward) {
@@ -1320,17 +1360,17 @@ size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
}
data += amount_to_forward;
len -= amount_to_forward;
- remaining_data_ -= amount_to_forward;
+ remaining_data_length_ -= amount_to_forward;
// If the FIN flag is set, and there is no more data in this data
// frame, inform the visitor of EOF via a 0-length data frame.
- if (!remaining_data_ && current_frame_flags_ & DATA_FLAG_FIN) {
+ if (!remaining_data_length_ && current_frame_flags_ & DATA_FLAG_FIN) {
visitor_->OnStreamFrameData(
current_frame_stream_id_, NULL, 0, DATA_FLAG_FIN);
}
}
- if (remaining_data_ == 0) {
+ if (remaining_data_length_ == 0) {
CHANGE_STATE(SPDY_AUTO_RESET);
}
return original_len - len;
@@ -1746,7 +1786,11 @@ SpdySerializedFrame* SpdyFramer::SerializeDataFrameHeader(
SpdyFrameBuilder builder(kSize);
builder.WriteDataFrameHeader(*this, data.stream_id(), flags);
- builder.OverwriteLength(*this, data.data().length());
+ if (protocol_version() < 4) {
+ builder.OverwriteLength(*this, data.data().length());
+ } else {
+ builder.OverwriteLength(*this, data.data().length() + kSize);
+ }
DCHECK_EQ(kSize, builder.length());
return builder.take();
}
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index 2772cab..c691d73 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -516,6 +516,8 @@ class NET_EXPORT_PRIVATE SpdyFramer {
FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ReadLargeSettingsFrame);
FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest,
ReadLargeSettingsFrameInSmallChunks);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ControlFrameAtMaxSizeLimit);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ControlFrameTooLarge);
friend class net::HttpNetworkLayer; // This is temporary for the server.
friend class net::HttpNetworkTransactionTest;
friend class net::HttpProxyClientSocketPoolTest;
@@ -597,7 +599,18 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// layer. We chose the framing layer, but this can be changed (or removed)
// if necessary later down the line.
size_t GetControlFrameBufferMaxSize() const {
- return (spdy_version_ == 2) ? 64 * 1024 : 16 * 1024 * 1024;
+ // The theoretical maximum for SPDY3 and earlier is (2^24 - 1) +
+ // 8, since the length field does not count the size of the
+ // header.
+ if (spdy_version_ == kSpdyVersion2) {
+ return 64 * 1024;
+ }
+ if (spdy_version_ == kSpdyVersion3) {
+ return 16 * 1024 * 1024;
+ }
+ // The theoretical maximum for SPDY4 is 2^16 - 1, as the length
+ // field does count the size of the header.
+ return 16 * 1024;
}
// The size of the control frame buffer.
@@ -609,11 +622,7 @@ class NET_EXPORT_PRIVATE SpdyFramer {
SpdyState state_;
SpdyState previous_state_;
SpdyError error_code_;
- size_t remaining_data_;
-
- // The number of bytes remaining to read from the current control frame's
- // payload.
- size_t remaining_control_payload_;
+ size_t remaining_data_length_;
// The number of bytes remaining to read from the current control frame's
// headers. Note that header data blocks (for control types that have them)
@@ -631,7 +640,7 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// The flags field of the frame currently being read.
uint8 current_frame_flags_;
- // The length field of the frame currently being read.
+ // The total length of the frame currently being read, including frame header.
uint32 current_frame_length_;
// The stream ID field of the frame currently being read, if applicable.
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 91d56ae..9a9f956 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -78,17 +78,22 @@ class SpdyFramerTestUtil {
SpdyFramer* framer, const SpdyFrameType& frame) {
DecompressionVisitor visitor(framer->protocol_version());
framer->set_visitor(&visitor);
- size_t input_size = frame.size();
- CHECK_EQ(input_size, framer->ProcessInput(frame.data(), input_size));
+ CHECK_EQ(frame.size(), framer->ProcessInput(frame.data(), frame.size()));
CHECK_EQ(SpdyFramer::SPDY_RESET, framer->state());
framer->set_visitor(NULL);
char* buffer = visitor.ReleaseBuffer();
CHECK(buffer != NULL);
SpdyFrame* decompressed_frame = new SpdyFrame(buffer, visitor.size(), true);
- SetFrameLength(decompressed_frame,
- visitor.size() - framer->GetControlFrameHeaderSize(),
- framer->protocol_version());
+ if (framer->protocol_version() == 4) {
+ SetFrameLength(decompressed_frame,
+ visitor.size(),
+ framer->protocol_version());
+ } else {
+ SetFrameLength(decompressed_frame,
+ visitor.size() - framer->GetControlFrameHeaderSize(),
+ framer->protocol_version());
+ }
return decompressed_frame;
}
@@ -267,6 +272,8 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
headers_frame_count_(0),
goaway_count_(0),
setting_count_(0),
+ last_window_update_stream_(0),
+ last_window_update_delta_(0),
data_bytes_(0),
fin_frame_count_(0),
fin_flag_count_(0),
@@ -471,10 +478,6 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
header_buffer_.reset(new char[header_buffer_size]);
}
- size_t control_frame_buffer_max_size() const {
- return framer_.GetControlFrameBufferMaxSize();
- }
-
static size_t header_data_chunk_max_size() {
return SpdyFramer::kHeaderDataChunkMaxSize;
}
@@ -541,6 +544,7 @@ namespace net {
enum SpdyFramerTestTypes {
SPDY2 = 2,
SPDY3 = 3,
+ SPDY4 = 4,
};
class SpdyFramerTest
@@ -611,6 +615,8 @@ class SpdyFramerTest
}
bool IsSpdy2() { return spdy_version_ == SPDY2; }
+ bool IsSpdy3() { return spdy_version_ == SPDY3; }
+ bool IsSpdy4() { return spdy_version_ == SPDY4; }
// Version of SPDY protocol to be used.
unsigned char spdy_version_;
@@ -619,7 +625,7 @@ class SpdyFramerTest
// All tests are run with two different SPDY versions: SPDY/2 and SPDY/3.
INSTANTIATE_TEST_CASE_P(SpdyFramerTests,
SpdyFramerTest,
- ::testing::Values(SPDY2, SPDY3));
+ ::testing::Values(SPDY2, SPDY3, SPDY4));
// Test that we can encode and decode a SpdyHeaderBlock in serialized form.
TEST_P(SpdyFramerTest, HeaderBlockInBuffer) {
@@ -720,7 +726,7 @@ TEST_P(SpdyFramerTest, CreateCredential) {
{
const char kDescription[] = "CREDENTIAL frame";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x80, spdy_version_, 0x00, 0x0A,
0x00, 0x00, 0x00, 0x33,
0x00, 0x03, 0x00, 0x00,
@@ -732,7 +738,23 @@ TEST_P(SpdyFramerTest, CreateCredential) {
0x0C, 'a', 'n', 'o',
't', 'h', 'e', 'r',
' ', 'c', 'e', 'r',
- 't', 0x00, 0x00, 0x00,
+ 't', 0x00, 0x00, 0x00,
+ 0x0A, 'f', 'i', 'n',
+ 'a', 'l', ' ', 'c',
+ 'e', 'r', 't',
+ };
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x37, 0x0A, 0x00,
+ 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x05, 'p', 'r',
+ 'o', 'o', 'f', 0x00,
+ 0x00, 0x00, 0x06, 'a',
+ ' ', 'c', 'e', 'r',
+ 't', 0x00, 0x00, 0x00,
+ 0x0C, 'a', 'n', 'o',
+ 't', 'h', 'e', 'r',
+ ' ', 'c', 'e', 'r',
+ 't', 0x00, 0x00, 0x00,
0x0A, 'f', 'i', 'n',
'a', 'l', ' ', 'c',
'e', 'r', 't',
@@ -744,7 +766,11 @@ TEST_P(SpdyFramerTest, CreateCredential) {
credential.certs.push_back("another cert");
credential.certs.push_back("final cert");
scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
}
@@ -752,7 +778,7 @@ TEST_P(SpdyFramerTest, ParseCredentialFrameData) {
SpdyFramer framer(spdy_version_);
{
- unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x80, spdy_version_, 0x00, 0x0A,
0x00, 0x00, 0x00, 0x33,
0x00, 0x03, 0x00, 0x00,
@@ -769,13 +795,37 @@ TEST_P(SpdyFramerTest, ParseCredentialFrameData) {
'a', 'l', ' ', 'c',
'e', 'r', 't',
};
- SpdyFrame frame(
- reinterpret_cast<char*>(kFrameData), arraysize(kFrameData), false);
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x37, 0x0A, 0x00,
+ 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x05, 'p', 'r',
+ 'o', 'o', 'f', 0x00,
+ 0x00, 0x00, 0x06, 'a',
+ ' ', 'c', 'e', 'r',
+ 't', 0x00, 0x00, 0x00,
+ 0x0C, 'a', 'n', 'o',
+ 't', 'h', 'e', 'r',
+ ' ', 'c', 'e', 'r',
+ 't', 0x00, 0x00, 0x00,
+ 0x0A, 'f', 'i', 'n',
+ 'a', 'l', ' ', 'c',
+ 'e', 'r', 't',
+ };
+
SpdyCredential credential;
- EXPECT_TRUE(SpdyFramer::ParseCredentialData(
- frame.data() + framer.GetControlFrameHeaderSize(),
- frame.size() - framer.GetControlFrameHeaderSize(),
- &credential));
+ if (IsSpdy4()) {
+ EXPECT_TRUE(SpdyFramer::ParseCredentialData(
+ reinterpret_cast<const char*>(kV4FrameData) +
+ framer.GetControlFrameHeaderSize(),
+ arraysize(kV4FrameData) - framer.GetControlFrameHeaderSize(),
+ &credential));
+ } else {
+ EXPECT_TRUE(SpdyFramer::ParseCredentialData(
+ reinterpret_cast<const char*>(kV3FrameData) +
+ framer.GetControlFrameHeaderSize(),
+ arraysize(kV3FrameData) - framer.GetControlFrameHeaderSize(),
+ &credential));
+ }
EXPECT_EQ(3u, credential.slot);
EXPECT_EQ("proof", credential.proof);
EXPECT_EQ("a cert", credential.certs.front());
@@ -1085,11 +1135,66 @@ TEST_P(SpdyFramerTest, Basic) {
0x00, 0x00, 0x00, 0x00,
};
+ const unsigned char kV4Input[] = {
+ 0x00, 0x1e, 0x01, 0x00, // SYN_STREAM #1
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x02, 'h', 'h',
+ 0x00, 0x00, 0x00, 0x02,
+ 'v', 'v',
+
+ 0x00, 0x24, 0x08, 0x00, // HEADERS on Stream #1
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x02,
+ 'h', '2', 0x00, 0x00,
+ 0x00, 0x02, 'v', '2',
+ 0x00, 0x00, 0x00, 0x02,
+ 'h', '3', 0x00, 0x00,
+ 0x00, 0x02, 'v', '3',
+
+ 0x00, 0x14, 0x00, 0x00, // DATA on Stream #1
+ 0x00, 0x00, 0x00, 0x01,
+ 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xbe, 0xef,
+
+ 0x00, 0x12, 0x01, 0x00, // SYN Stream #3
+ 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+
+ 0x00, 0x10, 0x00, 0x00, // DATA on Stream #3
+ 0x00, 0x00, 0x00, 0x03,
+ 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xbe, 0xef,
+
+ 0x00, 0x0c, 0x00, 0x00, // DATA on Stream #1
+ 0x00, 0x00, 0x00, 0x01,
+ 0xde, 0xad, 0xbe, 0xef,
+
+ 0x00, 0x0c, 0x03, 0x00, // RST_STREAM on Stream #1
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+
+ 0x00, 0x08, 0x00, 0x00, // DATA on Stream #3
+ 0x00, 0x00, 0x00, 0x03,
+
+ 0x00, 0x0c, 0x03, 0x00, // RST_STREAM on Stream #3
+ 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00,
+ };
+
TestSpdyVisitor visitor(spdy_version_);
if (IsSpdy2()) {
visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
- } else {
+ } else if (IsSpdy3()) {
visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
+ } else {
+ visitor.SimulateInFramer(kV4Input, sizeof(kV4Input));
}
EXPECT_EQ(0, visitor.error_count_);
@@ -1140,14 +1245,14 @@ TEST_P(SpdyFramerTest, FinOnDataFrame) {
0x00, 0x01, 0x00, 0x00,
0x00, 0x02, 'h', 'h',
0x00, 0x00, 0x00, 0x02,
- 'v', 'v',
+ 'v', 'v',
0x80, spdy_version_, 0x00, 0x02, // SYN REPLY Stream #1
0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x02,
- 'a', 'a', 0x00, 0x00,
+ 'a', 'a', 0x00, 0x00,
0x00, 0x02, 'b', 'b',
0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
@@ -1160,12 +1265,41 @@ TEST_P(SpdyFramerTest, FinOnDataFrame) {
0x01, 0x00, 0x00, 0x04,
0xde, 0xad, 0xbe, 0xef,
};
+ const unsigned char kV4Input[] = {
+ 0x00, 0x1e, 0x01, 0x00, // SYN_STREAM #1
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x02, 'h', 'h',
+ 0x00, 0x00, 0x00, 0x02,
+ 'v', 'v',
+
+ 0x00, 0x18, 0x02, 0x00, // SYN REPLY Stream #1
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02,
+ 'a', 'a', 0x00, 0x00,
+ 0x00, 0x02, 'b', 'b',
+
+ 0x00, 0x14, 0x00, 0x00, // DATA on Stream #1
+ 0x00, 0x00, 0x00, 0x01,
+ 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xbe, 0xef,
+
+ 0x00, 0x0c, 0x00, 0x01, // DATA on Stream #1, with FIN
+ 0x00, 0x00, 0x00, 0x01,
+ 0xde, 0xad, 0xbe, 0xef,
+ };
TestSpdyVisitor visitor(spdy_version_);
if (IsSpdy2()) {
visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
- } else {
+ } else if (IsSpdy3()) {
visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
+ } else {
+ visitor.SimulateInFramer(kV4Input, sizeof(kV4Input));
}
EXPECT_EQ(0, visitor.error_count_);
@@ -1216,12 +1350,31 @@ TEST_P(SpdyFramerTest, FinOnSynReplyFrame) {
'a', 'a', 0x00, 0x00,
0x00, 0x02, 'b', 'b',
};
+ const unsigned char kV4Input[] = {
+ 0x00, 0x1e, 0x01, 0x00, // SYN_STREAM #1
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x02, 'h', 'h',
+ 0x00, 0x00, 0x00, 0x02,
+ 'v', 'v',
+
+ 0x00, 0x18, 0x02, 0x01, // SYN_REPLY #1, with FIN
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02,
+ 'a', 'a', 0x00, 0x00,
+ 0x00, 0x02, 'b', 'b',
+ };
TestSpdyVisitor visitor(spdy_version_);
if (IsSpdy2()) {
visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
- } else {
+ } else if (IsSpdy3()) {
visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
+ } else {
+ visitor.SimulateInFramer(kV4Input, sizeof(kV4Input));
}
EXPECT_EQ(0, visitor.error_count_);
@@ -1418,19 +1571,26 @@ TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) {
TEST_P(SpdyFramerTest, WindowUpdateFrame) {
SpdyFramer framer(spdy_version_);
- scoped_ptr<SpdyFrame> window_update_frame(
- framer.CreateWindowUpdate(1, 0x12345678));
+ scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x12345678));
const char kDescription[] = "WINDOW_UPDATE frame, stream 1, delta 0x12345678";
- const unsigned char expected_data_frame[] = {
- 0x80, spdy_version_, 0x00, 0x09,
- 0x00, 0x00, 0x00, 0x08,
- 0x00, 0x00, 0x00, 0x01,
- 0x12, 0x34, 0x56, 0x78
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
+ 0x80, spdy_version_, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x12, 0x34, 0x56, 0x78
+ };
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0c, 0x09, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x12, 0x34, 0x56, 0x78
};
- CompareFrame(kDescription, *window_update_frame, expected_data_frame,
- arraysize(expected_data_frame));
+ if (IsSpdy4()) {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
TEST_P(SpdyFramerTest, CreateDataFrame) {
@@ -1438,17 +1598,29 @@ TEST_P(SpdyFramerTest, CreateDataFrame) {
{
const char kDescription[] = "'hello' data frame, no FIN";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x05,
- 'h', 'e', 'l', 'l',
+ 'h', 'e', 'l', 'l',
+ 'o'
+ };
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0d, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 'h', 'e', 'l', 'l',
'o'
};
const char bytes[] = "hello";
scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1, bytes, strlen(bytes), DATA_FLAG_NONE));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(
+ kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(
+ kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
SpdyDataIR data_ir(1);
data_ir.SetDataShallow(base::StringPiece(bytes, strlen(bytes)));
@@ -1457,60 +1629,107 @@ TEST_P(SpdyFramerTest, CreateDataFrame) {
kDescription,
reinterpret_cast<const unsigned char*>(frame->data()),
framer.GetDataFrameMinimumSize(),
- kFrameData,
+ IsSpdy4() ? kV4FrameData : kV3FrameData,
framer.GetDataFrameMinimumSize());
}
{
const char kDescription[] = "Data frame with negative data byte, no FIN";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01,
0xff
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0xff
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1, "\xff", 1, DATA_FLAG_NONE));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(
+ kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(
+ kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
{
const char kDescription[] = "'hello' data frame, with FIN";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x00, 0x00, 0x00, 0x01,
0x01, 0x00, 0x00, 0x05,
'h', 'e', 'l', 'l',
'o'
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0d, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01,
+ 'h', 'e', 'l', 'l',
+ 'o'
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1, "hello", 5, DATA_FLAG_FIN));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(
+ kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(
+ kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
{
const char kDescription[] = "Empty data frame";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1, "", 0, DATA_FLAG_NONE));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(
+ kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(
+ kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
{
const char kDescription[] = "Data frame with max stream ID";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x7f, 0xff, 0xff, 0xff,
0x01, 0x00, 0x00, 0x05,
- 'h', 'e', 'l', 'l',
+ 'h', 'e', 'l', 'l',
+ 'o'
+ };
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0d, 0x00, 0x01,
+ 0x7f, 0xff, 0xff, 0xff,
+ 'h', 'e', 'l', 'l',
'o'
};
scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
0x7fffffff, "hello", 5, DATA_FLAG_FIN));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(
+ kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(
+ kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
- {
+ if (!IsSpdy4()) {
+ // This test does not apply to SPDY 4 because the max frame size is smaller
+ // than 4MB.
const char kDescription[] = "Large data frame";
const int kDataSize = 4 * 1024 * 1024; // 4 MB
const string kData(kDataSize, 'A');
@@ -1571,6 +1790,20 @@ TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
0x00, 0x00, 0x03, 'b',
'a', 'r'
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x2e, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+ kPri, kCre, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x03, 'b', 'a',
+ 'r', 0x00, 0x00, 0x00,
+ 0x03, 'f', 'o', 'o',
+ 0x00, 0x00, 0x00, 0x03,
+ 'f', 'o', 'o', 0x00,
+ 0x00, 0x00, 0x03, 'b',
+ 'a', 'r'
+ };
scoped_ptr<SpdyFrame> frame(
framer.CreateSynStream(1, // stream id
0, // associated stream id
@@ -1579,10 +1812,13 @@ TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
CONTROL_FLAG_NONE,
false, // compress
&headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
{
@@ -1620,6 +1856,19 @@ TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
0x00, 0x00, 0x00, 0x03,
'b', 'a', 'r'
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x2b, 0x01, 0x01,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 'f', 'o',
+ 'o', 0x00, 0x00, 0x00,
+ 0x03, 'f', 'o', 'o',
+ 0x00, 0x00, 0x00, 0x03,
+ 'b', 'a', 'r'
+ };
scoped_ptr<SpdyFrame> frame(
framer.CreateSynStream(0x7fffffff, // stream id
0x7fffffff, // associated stream id
@@ -1628,10 +1877,13 @@ TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
CONTROL_FLAG_FIN,
false, // compress
&headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
{
@@ -1670,6 +1922,19 @@ TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
'f', 'o', 'o', 0x00,
0x00, 0x00, 0x00
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x2b, 0x01, 0x01,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x7f, 0xff, 0xff, 0xff,
+ kPri, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x03, 'b', 'a',
+ 'r', 0x00, 0x00, 0x00,
+ 0x03, 'f', 'o', 'o',
+ 0x00, 0x00, 0x00, 0x03,
+ 'f', 'o', 'o', 0x00,
+ 0x00, 0x00, 0x00
+ };
scoped_ptr<SpdyFrame> frame(
framer.CreateSynStream(0x7fffffff, // stream id
0x7fffffff, // associated stream id
@@ -1678,10 +1943,13 @@ TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
CONTROL_FLAG_FIN,
false, // compress
&headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
}
@@ -1737,6 +2005,23 @@ TEST_P(SpdyFramerTest, CreateSynStreamCompressed) {
0x80, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x3b, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x38, 0xea,
+ 0xe3, 0xc6, 0xa7, 0xc2,
+ 0x02, 0xe5, 0x0e, 0x50,
+ 0xc2, 0x4b, 0x4a, 0x04,
+ 0xe5, 0x0b, 0x66, 0x80,
+ 0x00, 0x4a, 0xcb, 0xcf,
+ 0x07, 0x08, 0x20, 0x10,
+ 0x95, 0x96, 0x9f, 0x0f,
+ 0xa2, 0x00, 0x02, 0x28,
+ 0x29, 0xb1, 0x08, 0x20,
+ 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff,
+ };
scoped_ptr<SpdyFrame> frame(
framer.CreateSynStream(1, // stream id
0, // associated stream id
@@ -1745,10 +2030,13 @@ TEST_P(SpdyFramerTest, CreateSynStreamCompressed) {
CONTROL_FLAG_NONE,
true, // compress
&headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
}
#endif // !defined(USE_SYSTEM_ZLIB)
@@ -1788,12 +2076,27 @@ TEST_P(SpdyFramerTest, CreateSynReplyUncompressed) {
'o', 0x00, 0x00, 0x00,
0x03, 'b', 'a', 'r'
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x28, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x03,
+ 'b', 'a', 'r', 0x00,
+ 0x00, 0x00, 0x03, 'f',
+ 'o', 'o', 0x00, 0x00,
+ 0x00, 0x03, 'f', 'o',
+ 'o', 0x00, 0x00, 0x00,
+ 0x03, 'b', 'a', 'r'
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
1, CONTROL_FLAG_NONE, false, &headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
{
@@ -1828,12 +2131,27 @@ TEST_P(SpdyFramerTest, CreateSynReplyUncompressed) {
0x00, 0x03, 'b', 'a',
'r'
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x25, 0x02, 0x01,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03,
+ 'f', 'o', 'o', 0x00,
+ 0x00, 0x00, 0x03, 'f',
+ 'o', 'o', 0x00, 0x00,
+ 0x00, 0x03, 'b', 'a',
+ 'r'
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
{
@@ -1868,12 +2186,27 @@ TEST_P(SpdyFramerTest, CreateSynReplyUncompressed) {
'o', 0x00, 0x00, 0x00,
0x00
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x25, 0x02, 0x01,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x03,
+ 'b', 'a', 'r', 0x00,
+ 0x00, 0x00, 0x03, 'f',
+ 'o', 'o', 0x00, 0x00,
+ 0x00, 0x03, 'f', 'o',
+ 'o', 0x00, 0x00, 0x00,
+ 0x00
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
}
@@ -1925,12 +2258,31 @@ TEST_P(SpdyFramerTest, CreateSynReplyCompressed) {
0x00, 0x00, 0x00, 0xff,
0xff,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x35, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x38, 0xea, 0xe3, 0xc6,
+ 0xa7, 0xc2, 0x02, 0xe5,
+ 0x0e, 0x50, 0xc2, 0x4b,
+ 0x4a, 0x04, 0xe5, 0x0b,
+ 0x66, 0x80, 0x00, 0x4a,
+ 0xcb, 0xcf, 0x07, 0x08,
+ 0x20, 0x10, 0x95, 0x96,
+ 0x9f, 0x0f, 0xa2, 0x00,
+ 0x02, 0x28, 0x29, 0xb1,
+ 0x08, 0x20, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0xff,
+ 0xff,
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
1, CONTROL_FLAG_NONE, true, &headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
}
#endif // !defined(USE_SYSTEM_ZLIB)
@@ -1940,41 +2292,68 @@ TEST_P(SpdyFramerTest, CreateRstStream) {
{
const char kDescription[] = "RST_STREAM frame";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x80, spdy_version_, 0x00, 0x03,
0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0c, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01,
+ };
scoped_ptr<SpdyFrame> frame(
framer.CreateRstStream(1, RST_STREAM_PROTOCOL_ERROR));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
{
const char kDescription[] = "RST_STREAM frame with max stream ID";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x80, spdy_version_, 0x00, 0x03,
0x00, 0x00, 0x00, 0x08,
0x7f, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x01,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0c, 0x03, 0x00,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x01,
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(
0x7FFFFFFF, RST_STREAM_PROTOCOL_ERROR));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
{
const char kDescription[] = "RST_STREAM frame with max status code";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x80, spdy_version_, 0x00, 0x03,
0x00, 0x00, 0x00, 0x08,
0x7f, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x06,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0c, 0x03, 0x00,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x06,
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(
0x7FFFFFFF, RST_STREAM_INTERNAL_ERROR));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
}
@@ -1994,27 +2373,35 @@ TEST_P(SpdyFramerTest, CreateSettings) {
EXPECT_EQ(kFlags, settings[kId].first);
EXPECT_EQ(kValue, settings[kId].second);
- const unsigned char kFrameDatav2[] = {
+ const unsigned char kV2FrameData[] = {
0x80, spdy_version_, 0x00, 0x04,
0x00, 0x00, 0x00, 0x0c,
0x00, 0x00, 0x00, 0x01,
0x04, 0x03, 0x02, 0x01,
0x0a, 0x0b, 0x0c, 0x0d,
};
-
- const unsigned char kFrameDatav3[] = {
+ const unsigned char kV3FrameData[] = {
0x80, spdy_version_, 0x00, 0x04,
0x00, 0x00, 0x00, 0x0c,
0x00, 0x00, 0x00, 0x01,
0x01, 0x02, 0x03, 0x04,
0x0a, 0x0b, 0x0c, 0x0d,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x10, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kFrameDatav2 : kFrameDatav3,
- arraysize(kFrameDatav3)); // Size is unchanged among versions.
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
{
@@ -2030,7 +2417,7 @@ TEST_P(SpdyFramerTest, CreateSettings) {
AddSpdySettingFromWireFormat(
&settings, 0x03000003, 0xff000004); // 4th Setting
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x80, spdy_version_, 0x00, 0x04,
0x00, 0x00, 0x00, 0x24,
0x00, 0x00, 0x00, 0x04,
@@ -2043,11 +2430,24 @@ TEST_P(SpdyFramerTest, CreateSettings) {
0x03, 0x00, 0x00, 0x03, // 4th Setting
0xff, 0x00, 0x00, 0x04,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x28, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, // 1st Setting
+ 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0x01, // 2nd Setting
+ 0x00, 0x00, 0x00, 0x02,
+ 0x02, 0x00, 0x00, 0x02, // 3rd Setting
+ 0x00, 0x00, 0x00, 0x03,
+ 0x03, 0x00, 0x00, 0x03, // 4th Setting
+ 0xff, 0x00, 0x00, 0x04,
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
- CompareFrame(kDescription,
- *frame,
- kFrameData,
- arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
{
@@ -2055,13 +2455,21 @@ TEST_P(SpdyFramerTest, CreateSettings) {
SettingsMap settings;
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x80, spdy_version_, 0x00, 0x04,
0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x08, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
}
@@ -2070,13 +2478,21 @@ TEST_P(SpdyFramerTest, CreatePingFrame) {
{
const char kDescription[] = "PING frame";
- const unsigned char kFrameData[] = {
- 0x80, spdy_version_, 0x00, 0x06,
- 0x00, 0x00, 0x00, 0x04,
- 0x12, 0x34, 0x56, 0x78,
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
+ 0x80, spdy_version_, 0x00, 0x06,
+ 0x00, 0x00, 0x00, 0x04,
+ 0x12, 0x34, 0x56, 0x78,
+ };
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x08, 0x06, 0x00,
+ 0x12, 0x34, 0x56, 0x78,
};
scoped_ptr<SpdyFrame> frame(framer.CreatePingFrame(0x12345678u));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
}
@@ -2096,11 +2512,19 @@ TEST_P(SpdyFramerTest, CreateGoAway) {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0c, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0, GOAWAY_OK));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
{
@@ -2116,12 +2540,20 @@ TEST_P(SpdyFramerTest, CreateGoAway) {
0x7f, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x02,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0c, 0x07, 0x00,
+ 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));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
}
@@ -2160,12 +2592,27 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
'o', 0x00, 0x00, 0x00,
0x03, 'b', 'a', 'r'
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x28, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x03,
+ 'b', 'a', 'r', 0x00,
+ 0x00, 0x00, 0x03, 'f',
+ 'o', 'o', 0x00, 0x00,
+ 0x00, 0x03, 'f', 'o',
+ 'o', 0x00, 0x00, 0x00,
+ 0x03, 'b', 'a', 'r'
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
1, CONTROL_FLAG_NONE, false, &headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
{
@@ -2200,12 +2647,27 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
0x00, 0x03, 'b', 'a',
'r'
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x25, 0x08, 0x01,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03,
+ 'f', 'o', 'o', 0x00,
+ 0x00, 0x00, 0x03, 'f',
+ 'o', 'o', 0x00, 0x00,
+ 0x00, 0x03, 'b', 'a',
+ 'r'
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
{
@@ -2240,12 +2702,27 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
'o', 0x00, 0x00, 0x00,
0x00
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x25, 0x08, 0x01,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x03,
+ 'b', 'a', 'r', 0x00,
+ 0x00, 0x00, 0x03, 'f',
+ 'o', 'o', 0x00, 0x00,
+ 0x00, 0x03, 'f', 'o',
+ 'o', 0x00, 0x00, 0x00,
+ 0x00
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
}
@@ -2297,12 +2774,31 @@ TEST_P(SpdyFramerTest, CreateHeadersCompressed) {
0x00, 0x00, 0x00, 0xff,
0xff,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x35, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x38, 0xea, 0xe3, 0xc6,
+ 0xa7, 0xc2, 0x02, 0xe5,
+ 0x0e, 0x50, 0xc2, 0x4b,
+ 0x4a, 0x04, 0xe5, 0x0b,
+ 0x66, 0x80, 0x00, 0x4a,
+ 0xcb, 0xcf, 0x07, 0x08,
+ 0x20, 0x10, 0x95, 0x96,
+ 0x9f, 0x0f, 0xa2, 0x00,
+ 0x02, 0x28, 0x29, 0xb1,
+ 0x08, 0x20, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0xff,
+ 0xff
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
1, CONTROL_FLAG_NONE, true, &headers));
- CompareFrame(kDescription,
- *frame,
- IsSpdy2() ? kV2FrameData : kV3FrameData,
- IsSpdy2() ? arraysize(kV2FrameData) : arraysize(kV3FrameData));
+ if (IsSpdy2()) {
+ CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+ } else if (IsSpdy3()) {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
}
}
#endif // !defined(USE_SYSTEM_ZLIB)
@@ -2312,39 +2808,66 @@ TEST_P(SpdyFramerTest, CreateWindowUpdate) {
{
const char kDescription[] = "WINDOW_UPDATE frame";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x80, spdy_version_, 0x00, 0x09,
0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0c, 0x09, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01,
+ };
scoped_ptr<SpdyFrame> frame(
framer.CreateWindowUpdate(1, 1));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
{
const char kDescription[] = "WINDOW_UPDATE frame with max stream ID";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x80, spdy_version_, 0x00, 0x09,
0x00, 0x00, 0x00, 0x08,
0x7f, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x01,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0c, 0x09, 0x00,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x01,
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(0x7FFFFFFF, 1));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
{
const char kDescription[] = "WINDOW_UPDATE frame with max window delta";
- const unsigned char kFrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x80, spdy_version_, 0x00, 0x09,
0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x01,
0x7f, 0xff, 0xff, 0xff,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0c, 0x09, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x7f, 0xff, 0xff, 0xff,
+ };
scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x7FFFFFFF));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ if (IsSpdy4()) {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ } else {
+ CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+ }
}
}
@@ -2446,25 +2969,12 @@ TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) {
}
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;
- TestSpdyVisitor visitor(spdy_version_);
- const size_t big_value_size =
- visitor.control_frame_buffer_max_size() - overhead;
- std::string big_value(big_value_size, 'x');
- headers["aa"] = big_value.c_str();
+ // First find the size of the header value in order to just reach the control
+ // frame max size.
SpdyFramer framer(spdy_version_);
framer.set_enable_compression(false);
+ SpdyHeaderBlock headers;
+ headers["aa"] = "";
scoped_ptr<SpdyFrame> control_frame(
framer.CreateSynStream(1, // stream_id
0, // associated_stream_id
@@ -2473,7 +2983,24 @@ TEST_P(SpdyFramerTest, ControlFrameAtMaxSizeLimit) {
CONTROL_FLAG_NONE,
false, // compress
&headers));
+ const size_t kBigValueSize =
+ framer.GetControlFrameBufferMaxSize() - control_frame->size();
+
+ // Create a frame at exatly that size.
+ string big_value(kBigValueSize, 'x');
+ headers["aa"] = big_value.c_str();
+ control_frame.reset(
+ 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);
+ EXPECT_EQ(framer.GetControlFrameBufferMaxSize(), control_frame->size());
+
+ TestSpdyVisitor visitor(spdy_version_);
visitor.SimulateInFramer(
reinterpret_cast<unsigned char*>(control_frame->data()),
control_frame->size());
@@ -2482,21 +3009,16 @@ TEST_P(SpdyFramerTest, ControlFrameAtMaxSizeLimit) {
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_);
+ EXPECT_LT(kBigValueSize, 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;
- TestSpdyVisitor visitor(spdy_version_);
- const size_t kBigValueSize =
- visitor.control_frame_buffer_max_size() - overhead;
- std::string big_value(kBigValueSize, 'x');
- headers["aa"] = big_value.c_str();
+ // First find the size of the header value in order to just reach the control
+ // frame max size.
SpdyFramer framer(spdy_version_);
framer.set_enable_compression(false);
+ SpdyHeaderBlock headers;
+ headers["aa"] = "";
scoped_ptr<SpdyFrame> control_frame(
framer.CreateSynStream(1, // stream_id
0, // associated_stream_id
@@ -2505,7 +3027,25 @@ TEST_P(SpdyFramerTest, ControlFrameTooLarge) {
CONTROL_FLAG_NONE,
false, // compress
&headers));
+ const size_t kBigValueSize =
+ framer.GetControlFrameBufferMaxSize() - control_frame->size() + 1;
+
+ // Create a frame at exatly that size.
+ string big_value(kBigValueSize, 'x');
+ headers["aa"] = big_value.c_str();
+ control_frame.reset(
+ 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);
+ EXPECT_EQ(framer.GetControlFrameBufferMaxSize() + 1,
+ control_frame->size());
+
+ TestSpdyVisitor visitor(spdy_version_);
visitor.SimulateInFramer(
reinterpret_cast<unsigned char*>(control_frame->data()),
control_frame->size());
@@ -2525,8 +3065,8 @@ TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) {
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');
+ const size_t kBigValueSize = kHeaderBufferSize * 2;
+ string big_value(kBigValueSize, 'x');
headers["aa"] = big_value.c_str();
SpdyFramer framer(spdy_version_);
scoped_ptr<SpdyFrame> control_frame(
@@ -2593,28 +3133,28 @@ TEST_P(SpdyFramerTest, DecompressCorruptHeaderBlock) {
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.
- ASSERT_GE(254u, SpdyFramer::kControlFrameBufferSize);
+ ASSERT_GE(250u, SpdyFramer::kControlFrameBufferSize);
const unsigned char length = 1 + SpdyFramer::kControlFrameBufferSize;
- const unsigned char kV2FrameData[] = {
+ const unsigned char kV3FrameData[] = { // Also applies for V2.
0x80, spdy_version_, 0x00, 0x07,
0x00, 0x00, 0x00, length,
0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
};
- const unsigned char kV3FrameData[] = {
- 0x80, spdy_version_, 0x00, 0x07,
- 0x00, 0x00, 0x00, length,
+ const unsigned char kV4FrameData[] = {
+ 0x00, static_cast<uint8>(length + 4), 0x07, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
SpdyFramer framer(spdy_version_);
const size_t pad_length =
length + framer.GetControlFrameHeaderSize() -
- (IsSpdy2() ? sizeof(kV2FrameData) : sizeof(kV3FrameData));
+ (IsSpdy4() ? sizeof(kV4FrameData) : sizeof(kV3FrameData));
string pad('A', pad_length);
TestSpdyVisitor visitor(spdy_version_);
- if (IsSpdy2()) {
- visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData));
+ if (IsSpdy4()) {
+ visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData));
} else {
visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
}
@@ -2716,7 +3256,6 @@ TEST_P(SpdyFramerTest, ReadDuplicateSettings) {
0x03, 0x00, 0x00, 0x00, // 3rd (unprocessed) Setting
0x00, 0x00, 0x00, 0x03,
};
-
const unsigned char kV3FrameData[] = {
0x80, spdy_version_, 0x00, 0x04,
0x00, 0x00, 0x00, 0x1C,
@@ -2728,13 +3267,25 @@ TEST_P(SpdyFramerTest, ReadDuplicateSettings) {
0x00, 0x00, 0x00, 0x03, // 3rd (unprocessed) Setting
0x00, 0x00, 0x00, 0x03,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x20, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x01, // 1st Setting
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x01, // 2nd (duplicate) Setting
+ 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x03, // 3rd (unprocessed) Setting
+ 0x00, 0x00, 0x00, 0x03,
+ };
TestSpdyVisitor visitor(spdy_version_);
visitor.use_compression_ = false;
if (IsSpdy2()) {
visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData));
- } else {
+ } else if (IsSpdy3()) {
visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
+ } else {
+ visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData));
}
EXPECT_EQ(1, visitor.error_count_);
EXPECT_EQ(1, visitor.setting_count_);
@@ -2755,7 +3306,6 @@ TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) {
0x03, 0x00, 0x00, 0x00, // 3rd (unprocessed) Setting
0x00, 0x00, 0x00, 0x03,
};
-
const unsigned char kV3FrameData[] = {
0x80, spdy_version_, 0x00, 0x04,
0x00, 0x00, 0x00, 0x1C,
@@ -2767,13 +3317,25 @@ TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) {
0x00, 0x00, 0x01, 0x03, // 3rd (unprocessed) Setting
0x00, 0x00, 0x00, 0x03,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x20, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x02, // 1st Setting
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x01, // 2nd (out of order) Setting
+ 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x01, 0x03, // 3rd (unprocessed) Setting
+ 0x00, 0x00, 0x00, 0x03,
+ };
TestSpdyVisitor visitor(spdy_version_);
visitor.use_compression_ = false;
if (IsSpdy2()) {
visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData));
- } else {
+ } else if (IsSpdy3()) {
visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
+ } else {
+ visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData));
}
EXPECT_EQ(1, visitor.error_count_);
EXPECT_EQ(1, visitor.setting_count_);
@@ -2924,6 +3486,10 @@ TEST_P(SpdyFramerTest, ReadGarbage) {
}
TEST_P(SpdyFramerTest, ReadGarbageWithValidVersion) {
+ if (IsSpdy4()) {
+ // Not valid for SPDY 4 since there is no version field.
+ return;
+ }
SpdyFramer framer(spdy_version_);
const unsigned char kFrameData[] = {
0x80, spdy_version_, 0xff, 0xff,
@@ -2937,20 +3503,30 @@ TEST_P(SpdyFramerTest, ReadGarbageWithValidVersion) {
TEST_P(SpdyFramerTest, SizesTest) {
SpdyFramer framer(spdy_version_);
- EXPECT_EQ(8u, framer.GetControlFrameHeaderSize());
- EXPECT_EQ(18u, framer.GetSynStreamMinimumSize());
- EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetSynReplyMinimumSize());
- EXPECT_EQ(16u, framer.GetRstStreamSize());
- EXPECT_EQ(8u, framer.GetControlFrameHeaderSize());
- EXPECT_EQ(18u, framer.GetSynStreamMinimumSize());
- EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetSynReplyMinimumSize());
- EXPECT_EQ(16u, framer.GetRstStreamSize());
- EXPECT_EQ(12u, framer.GetSettingsMinimumSize());
- EXPECT_EQ(12u, framer.GetPingSize());
- EXPECT_EQ(IsSpdy2() ? 12u : 16u, framer.GetGoAwaySize());
- EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetHeadersMinimumSize());
- EXPECT_EQ(16u, framer.GetWindowUpdateSize());
- EXPECT_EQ(10u, framer.GetCredentialMinimumSize());
+ EXPECT_EQ(8u, framer.GetDataFrameMinimumSize());
+ if (IsSpdy4()) {
+ EXPECT_EQ(4u, framer.GetControlFrameHeaderSize());
+ EXPECT_EQ(14u, framer.GetSynStreamMinimumSize());
+ EXPECT_EQ(8u, framer.GetSynReplyMinimumSize());
+ EXPECT_EQ(12u, framer.GetRstStreamSize());
+ EXPECT_EQ(8u, framer.GetSettingsMinimumSize());
+ EXPECT_EQ(8u, framer.GetPingSize());
+ EXPECT_EQ(12u, framer.GetGoAwaySize());
+ EXPECT_EQ(8u, framer.GetHeadersMinimumSize());
+ EXPECT_EQ(12u, framer.GetWindowUpdateSize());
+ EXPECT_EQ(6u, framer.GetCredentialMinimumSize());
+ } else {
+ EXPECT_EQ(8u, framer.GetControlFrameHeaderSize());
+ EXPECT_EQ(18u, framer.GetSynStreamMinimumSize());
+ EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetSynReplyMinimumSize());
+ EXPECT_EQ(16u, framer.GetRstStreamSize());
+ EXPECT_EQ(12u, framer.GetSettingsMinimumSize());
+ EXPECT_EQ(12u, framer.GetPingSize());
+ EXPECT_EQ(IsSpdy2() ? 12u : 16u, framer.GetGoAwaySize());
+ EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetHeadersMinimumSize());
+ EXPECT_EQ(16u, framer.GetWindowUpdateSize());
+ EXPECT_EQ(10u, framer.GetCredentialMinimumSize());
+ }
}
TEST_P(SpdyFramerTest, StateToStringTest) {
@@ -3067,6 +3643,10 @@ TEST_P(SpdyFramerTest, ControlTypeToStringTest) {
}
TEST_P(SpdyFramerTest, CatchProbableHttpResponse) {
+ if (IsSpdy4()) {
+ // TODO(hkhalil): catch probable HTTP response in SPDY 4?
+ return;
+ }
{
testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
@@ -3129,7 +3709,7 @@ TEST_P(SpdyFramerTest, SynStreamFrameFlags) {
for (int flags = 0; flags < 256; ++flags) {
SCOPED_TRACE(testing::Message() << "Flags " << flags);
- testing::StrictMock<net::test::MockVisitor> visitor;
+ testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
@@ -3169,7 +3749,7 @@ TEST_P(SpdyFramerTest, SynReplyFrameFlags) {
for (int flags = 0; flags < 256; ++flags) {
SCOPED_TRACE(testing::Message() << "Flags " << flags);
- testing::StrictMock<net::test::MockVisitor> visitor;
+ testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
@@ -3206,7 +3786,7 @@ TEST_P(SpdyFramerTest, RstStreamFrameFlags) {
for (int flags = 0; flags < 256; ++flags) {
SCOPED_TRACE(testing::Message() << "Flags " << flags);
- testing::StrictMock<net::test::MockVisitor> visitor;
+ testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
@@ -3235,7 +3815,7 @@ TEST_P(SpdyFramerTest, SettingsFrameFlags) {
for (int flags = 0; flags < 256; ++flags) {
SCOPED_TRACE(testing::Message() << "Flags " << flags);
- testing::StrictMock<net::test::MockVisitor> visitor;
+ testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
@@ -3268,7 +3848,7 @@ TEST_P(SpdyFramerTest, GoawayFrameFlags) {
for (int flags = 0; flags < 256; ++flags) {
SCOPED_TRACE(testing::Message() << "Flags " << flags);
- testing::StrictMock<net::test::MockVisitor> visitor;
+ testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
@@ -3297,7 +3877,7 @@ TEST_P(SpdyFramerTest, HeadersFrameFlags) {
for (int flags = 0; flags < 256; ++flags) {
SCOPED_TRACE(testing::Message() << "Flags " << flags);
- testing::StrictMock<net::test::MockVisitor> visitor;
+ testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
@@ -3334,7 +3914,7 @@ TEST_P(SpdyFramerTest, PingFrameFlags) {
for (int flags = 0; flags < 256; ++flags) {
SCOPED_TRACE(testing::Message() << "Flags " << flags);
- testing::StrictMock<net::test::MockVisitor> visitor;
+ testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
@@ -3363,7 +3943,7 @@ TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) {
for (int flags = 0; flags < 256; ++flags) {
SCOPED_TRACE(testing::Message() << "Flags " << flags);
- testing::StrictMock<net::test::MockVisitor> visitor;
+ testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
@@ -3392,7 +3972,7 @@ TEST_P(SpdyFramerTest, CredentialFrameFlags) {
for (int flags = 0; flags < 256; ++flags) {
SCOPED_TRACE(testing::Message() << "Flags " << flags);
- testing::StrictMock<net::test::MockVisitor> visitor;
+ testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
@@ -3431,10 +4011,17 @@ TEST_P(SpdyFramerTest, EmptySynStream) {
frame(framer.CreateSynStream(1, 0, 1, 0, CONTROL_FLAG_NONE, true,
&headers));
// Adjust size to remove the name/value block.
- SetFrameLength(
- frame.get(),
- framer.GetSynStreamMinimumSize() - framer.GetControlFrameHeaderSize(),
- spdy_version_);
+ if (IsSpdy4()) {
+ SetFrameLength(
+ frame.get(),
+ framer.GetSynStreamMinimumSize(),
+ spdy_version_);
+ } else {
+ SetFrameLength(
+ frame.get(),
+ framer.GetSynStreamMinimumSize() - framer.GetControlFrameHeaderSize(),
+ spdy_version_);
+ }
EXPECT_CALL(visitor, OnSynStream(1, 0, 1, 0, false, false));
EXPECT_CALL(visitor, OnControlFrameHeaderData(1, NULL, 0));
@@ -3460,33 +4047,55 @@ TEST_P(SpdyFramerTest, SettingsFlagsAndId) {
TEST_P(SpdyFramerTest, RstStreamStatusBounds) {
DCHECK_GE(0xff, RST_STREAM_NUM_STATUS_CODES);
- const unsigned char kRstStreamInvalid[] = {
+ const unsigned char kV3RstStreamInvalid[] = {
0x80, spdy_version_, 0x00, 0x03,
0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, RST_STREAM_INVALID
};
+ const unsigned char kV4RstStreamInvalid[] = {
+ 0x00, 0x0c, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, RST_STREAM_INVALID
+ };
- const unsigned char kRstStreamNumStatusCodes[] = {
+ const unsigned char kV3RstStreamNumStatusCodes[] = {
0x80, spdy_version_, 0x00, 0x03,
0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, RST_STREAM_NUM_STATUS_CODES
};
+ const unsigned char kV4RstStreamNumStatusCodes[] = {
+ 0x00, 0x0c, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, RST_STREAM_NUM_STATUS_CODES
+ };
- testing::StrictMock<net::test::MockVisitor> visitor;
+ testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
- framer.ProcessInput(reinterpret_cast<const char*>(kRstStreamInvalid),
- arraysize(kRstStreamInvalid));
+ if (IsSpdy4()) {
+ framer.ProcessInput(reinterpret_cast<const char*>(kV4RstStreamInvalid),
+ arraysize(kV4RstStreamInvalid));
+ } else {
+ framer.ProcessInput(reinterpret_cast<const char*>(kV3RstStreamInvalid),
+ arraysize(kV3RstStreamInvalid));
+ }
EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
- framer.ProcessInput(reinterpret_cast<const char*>(kRstStreamNumStatusCodes),
- arraysize(kRstStreamNumStatusCodes));
+ if (IsSpdy4()) {
+ framer.ProcessInput(
+ reinterpret_cast<const char*>(kV4RstStreamNumStatusCodes),
+ arraysize(kV4RstStreamNumStatusCodes));
+ } else {
+ framer.ProcessInput(
+ reinterpret_cast<const char*>(kV3RstStreamNumStatusCodes),
+ arraysize(kV3RstStreamNumStatusCodes));
+ }
EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
}
@@ -3504,8 +4113,13 @@ TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) {
0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00,
};
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x0c, 0x07, 0x00,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ };
- testing::StrictMock<net::test::MockVisitor> visitor;
+ testing::StrictMock<test::MockVisitor> visitor;
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
@@ -3513,9 +4127,12 @@ TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) {
if (IsSpdy2()) {
framer.ProcessInput(reinterpret_cast<const char*>(kV2FrameData),
arraysize(kV2FrameData));
- } else {
+ } else if (IsSpdy3()) {
framer.ProcessInput(reinterpret_cast<const char*>(kV3FrameData),
arraysize(kV3FrameData));
+ } else {
+ framer.ProcessInput(reinterpret_cast<const char*>(kV4FrameData),
+ arraysize(kV4FrameData));
}
EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
diff --git a/net/spdy/spdy_test_utils.cc b/net/spdy/spdy_test_utils.cc
index 69a7f86..9a7401b 100644
--- a/net/spdy/spdy_test_utils.cc
+++ b/net/spdy/spdy_test_utils.cc
@@ -88,6 +88,9 @@ void SetFrameFlags(SpdyFrame* frame, uint8 flags, int spdy_version) {
case 3:
frame->data()[4] = flags;
break;
+ case 4:
+ frame->data()[3] = flags;
+ break;
default:
LOG(FATAL) << "Unsupported SPDY version.";
}
@@ -105,6 +108,15 @@ void SetFrameLength(SpdyFrame* frame, size_t length, int spdy_version) {
memcpy(frame->data() + 5, reinterpret_cast<char*>(&wire_length) + 1, 3);
}
break;
+ case 4:
+ CHECK_GT(1u<<16, length);
+ {
+ int32 wire_length = htons(static_cast<uint16>(length));
+ memcpy(frame->data(),
+ reinterpret_cast<char*>(&wire_length),
+ sizeof(uint16));
+ }
+ break;
default:
LOG(FATAL) << "Unsupported SPDY version.";
}