| 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();
|
|
|