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

Unified Diff: net/spdy/spdy_framer.cc

Issue 199843005: Implement padding for SPDY4/HTTP2 DATA frames. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: nullptr => NULL & discard padding at SpdySession visitor call. Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/spdy/spdy_framer.h ('k') | net/spdy/spdy_framer_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/spdy/spdy_framer.cc
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index 1c0ee752ff3f54f14434aea940fdb287c99332b2..2d18e0c56b4dd444b57c65fc893d4383e439f463 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -161,6 +161,8 @@ void SpdyFramer::Reset() {
current_frame_length_ = 0;
current_frame_stream_id_ = kInvalidStream;
settings_scratch_.Reset();
+ remaining_padding_payload_length_ = 0;
+ remaining_padding_length_fields_ = 0;
}
size_t SpdyFramer::GetDataFrameMinimumSize() const {
@@ -349,6 +351,10 @@ const char* SpdyFramer::StateToString(int state) {
return "READING_COMMON_HEADER";
case SPDY_CONTROL_FRAME_PAYLOAD:
return "CONTROL_FRAME_PAYLOAD";
+ case SPDY_READ_PADDING_LENGTH:
+ return "SPDY_READ_PADDING_LENGTH";
+ case SPDY_CONSUME_PADDING:
+ return "SPDY_CONSUME_PADDING";
case SPDY_IGNORE_REMAINING_PAYLOAD:
return "IGNORE_REMAINING_PAYLOAD";
case SPDY_FORWARD_STREAM_FRAME:
@@ -552,6 +558,20 @@ size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
break;
}
+ case SPDY_READ_PADDING_LENGTH: {
+ size_t bytes_read = ProcessFramePaddingLength(data, len);
+ len -= bytes_read;
+ data += bytes_read;
+ break;
+ }
+
+ case SPDY_CONSUME_PADDING: {
+ size_t bytes_read = ProcessFramePadding(data, len);
+ len -= bytes_read;
+ data += bytes_read;
+ break;
+ }
+
case SPDY_IGNORE_REMAINING_PAYLOAD:
// control frame has too-large payload
// intentional fallthrough
@@ -705,14 +725,22 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
<< "DATA frame too large for SPDY >= 4.";
}
- if (current_frame_flags_ & ~DATA_FLAG_FIN) {
+ uint8 valid_data_flags = 0;
+ if (protocol_version() >= 4) {
+ valid_data_flags = DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT |
+ DATA_FLAG_PAD_LOW | DATA_FLAG_PAD_HIGH;
+ } else {
+ valid_data_flags = DATA_FLAG_FIN;
+ }
+
+ if (current_frame_flags_ & ~valid_data_flags) {
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);
+ CHANGE_STATE(SPDY_READ_PADDING_LENGTH);
} else {
// Empty data frame.
if (current_frame_flags_ & DATA_FLAG_FIN) {
@@ -1815,11 +1843,87 @@ size_t SpdyFramer::ProcessRstStreamFramePayload(const char* data, size_t len) {
return original_len;
}
-size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
+size_t SpdyFramer::ProcessFramePaddingLength(const char* data, size_t len) {
+ DCHECK_EQ(SPDY_READ_PADDING_LENGTH, state_);
+
+ size_t original_len = len;
+ if (remaining_padding_length_fields_ == 0) {
+ DCHECK_EQ(remaining_padding_payload_length_, 0u);
+ bool pad_low = false;
+ bool pad_high = false;
+ if (current_frame_flags_ & net::DATA_FLAG_PAD_LOW) {
+ pad_low = true;
+ ++remaining_padding_length_fields_;
+ }
+ if (current_frame_flags_ & net::DATA_FLAG_PAD_HIGH) {
+ pad_high = true;
+ ++remaining_padding_length_fields_;
+ }
+ if ((pad_high && !pad_low) ||
+ remaining_data_length_ < remaining_padding_length_fields_) {
+ set_error(SPDY_INVALID_DATA_FRAME_FLAGS);
+ return 0;
+ }
+ }
+
+ // Parse the padding length.
+ while (len != 0 && remaining_padding_length_fields_ != 0) {
+ remaining_padding_payload_length_ =
+ (remaining_padding_payload_length_ << 8) +
+ *reinterpret_cast<const uint8*>(data);
+ ++data;
+ --len;
+ --remaining_padding_length_fields_;
+ --remaining_data_length_;
+ }
+
+ if (remaining_padding_length_fields_ == 0) {
+ if (remaining_padding_payload_length_ > remaining_data_length_) {
+ set_error(SPDY_INVALID_DATA_FRAME_FLAGS);
+ return 0;
+ }
+ CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
+ }
+ return original_len - len;
+}
+
+size_t SpdyFramer::ProcessFramePadding(const char* data, size_t len) {
+ DCHECK_EQ(SPDY_CONSUME_PADDING, state_);
+
size_t original_len = len;
+ if (remaining_padding_payload_length_ > 0) {
+ DCHECK_EQ(remaining_padding_payload_length_, remaining_data_length_);
+ size_t amount_to_discard = std::min(remaining_padding_payload_length_, len);
+ // The visitor needs to know about padding so it can send window updates.
+ // Communicate the padding to the visitor through a NULL data pointer, with
+ // a nonzero size.
+ if (amount_to_discard) {
+ visitor_->OnStreamFrameData(
+ current_frame_stream_id_, NULL, amount_to_discard, false);
+ }
+ data += amount_to_discard;
+ len -= amount_to_discard;
+ remaining_padding_payload_length_ -= amount_to_discard;
+ remaining_data_length_ -= amount_to_discard;
- if (remaining_data_length_ > 0) {
- size_t amount_to_forward = std::min(remaining_data_length_, len);
+ // 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_length_ && current_frame_flags_ & DATA_FLAG_FIN) {
+ visitor_->OnStreamFrameData(current_frame_stream_id_, NULL, 0, true);
+ }
+ }
+
+ if (remaining_data_length_ == 0) {
+ CHANGE_STATE(SPDY_AUTO_RESET);
+ }
+ return original_len - len;
+}
+
+size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
+ size_t original_len = len;
+ if (remaining_data_length_ - remaining_padding_payload_length_ > 0) {
+ size_t amount_to_forward = std::min(
+ remaining_data_length_ - remaining_padding_payload_length_, len);
if (amount_to_forward && state_ != SPDY_IGNORE_REMAINING_PAYLOAD) {
// Only inform the visitor if there is data.
if (amount_to_forward) {
@@ -1838,8 +1942,8 @@ size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
}
}
- if (remaining_data_length_ == 0) {
- CHANGE_STATE(SPDY_AUTO_RESET);
+ if (remaining_data_length_ == remaining_padding_payload_length_) {
+ CHANGE_STATE(SPDY_CONSUME_PADDING);
}
return original_len - len;
}
@@ -1900,36 +2004,74 @@ size_t SpdyFramer::ParseHeaderBlockInBuffer(const char* header_data,
return reader.GetBytesConsumed();
}
-SpdySerializedFrame* SpdyFramer::SerializeData(const SpdyDataIR& data) const {
- const size_t kSize = GetDataFrameMinimumSize() + data.data().length();
-
- SpdyDataFlags flags = DATA_FLAG_NONE;
- if (data.fin()) {
+SpdySerializedFrame* SpdyFramer::SerializeData(const SpdyDataIR& datair) const {
+ uint8 flags = DATA_FLAG_NONE;
+ if (datair.fin()) {
flags = DATA_FLAG_FIN;
}
- SpdyFrameBuilder builder(kSize);
- builder.WriteDataFrameHeader(*this, data.stream_id(), flags);
- builder.WriteBytes(data.data().data(), data.data().length());
- DCHECK_EQ(kSize, builder.length());
- return builder.take();
+ if (protocol_version() >= 4) {
+ int num_padding_fields = 0;
+ if (datair.pad_low()) {
+ flags |= DATA_FLAG_PAD_LOW;
+ ++num_padding_fields;
+ }
+ if (datair.pad_high()) {
+ flags |= DATA_FLAG_PAD_HIGH;
+ ++num_padding_fields;
+ }
+
+ const size_t size_with_padding = num_padding_fields +
+ datair.data().length() + datair.padding_payload_len() +
+ GetDataFrameMinimumSize();
+ SpdyFrameBuilder builder(size_with_padding);
+ builder.WriteDataFrameHeader(*this, datair.stream_id(), flags);
+ if (datair.pad_high()) {
+ builder.WriteUInt8(datair.padding_payload_len() >> 8);
+ }
+ if (datair.pad_low()) {
+ builder.WriteUInt8(datair.padding_payload_len() & 0xff);
+ }
+ builder.WriteBytes(datair.data().data(), datair.data().length());
+ if (datair.padding_payload_len() > 0) {
+ string padding = string(datair.padding_payload_len(), '0');
+ builder.WriteBytes(padding.data(), padding.length());
+ }
+ DCHECK_EQ(size_with_padding, builder.length());
+ return builder.take();
+ } else {
+ const size_t size = GetDataFrameMinimumSize() + datair.data().length();
+ SpdyFrameBuilder builder(size);
+ builder.WriteDataFrameHeader(*this, datair.stream_id(), flags);
+ builder.WriteBytes(datair.data().data(), datair.data().length());
+ DCHECK_EQ(size, builder.length());
+ return builder.take();
+ }
}
SpdySerializedFrame* SpdyFramer::SerializeDataFrameHeader(
const SpdyDataIR& data) const {
const size_t kSize = GetDataFrameMinimumSize();
- SpdyDataFlags flags = DATA_FLAG_NONE;
+ uint8 flags = DATA_FLAG_NONE;
if (data.fin()) {
flags = DATA_FLAG_FIN;
}
+ if (protocol_version() >= 4) {
+ if (data.pad_low()) {
+ flags |= DATA_FLAG_PAD_LOW;
+ }
+ if (data.pad_high()) {
+ flags |= DATA_FLAG_PAD_HIGH;
+ }
+ }
SpdyFrameBuilder builder(kSize);
builder.WriteDataFrameHeader(*this, data.stream_id(), flags);
- if (protocol_version() < 4) {
- builder.OverwriteLength(*this, data.data().length());
- } else {
+ if (protocol_version() >= 4) {
builder.OverwriteLength(*this, data.data().length() + kSize);
+ } else {
+ builder.OverwriteLength(*this, data.data().length());
}
DCHECK_EQ(kSize, builder.length());
return builder.take();
« no previous file with comments | « net/spdy/spdy_framer.h ('k') | net/spdy/spdy_framer_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698