| Index: net/spdy/spdy_framer.cc
|
| diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
|
| index f7b52831d7912d9bf166f3bbfb55f35d2559c948..7153ad491dab20cb42ac2e8882d93eac4956e980 100644
|
| --- a/net/spdy/spdy_framer.cc
|
| +++ b/net/spdy/spdy_framer.cc
|
| @@ -929,9 +929,11 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
|
| } else if (protocol_version() <= SPDY3 &&
|
| current_frame_flags_ & ~CONTROL_FLAG_FIN) {
|
| set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
|
| - } else if (protocol_version() > SPDY3 && current_frame_flags_ &
|
| - ~(CONTROL_FLAG_FIN | HEADERS_FLAG_PRIORITY |
|
| - HEADERS_FLAG_END_HEADERS)) {
|
| + } else if (protocol_version() > SPDY3 &&
|
| + current_frame_flags_ &
|
| + ~(CONTROL_FLAG_FIN | HEADERS_FLAG_PRIORITY |
|
| + HEADERS_FLAG_END_HEADERS | HEADERS_FLAG_END_SEGMENT |
|
| + HEADERS_FLAG_PAD_LOW | HEADERS_FLAG_PAD_HIGH)) {
|
| set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
|
| }
|
| }
|
| @@ -957,8 +959,10 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
|
| set_error(SPDY_INVALID_CONTROL_FRAME);
|
| } else if (protocol_version() <= SPDY3 && current_frame_flags_ != 0) {
|
| set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
|
| - } else if (protocol_version() > SPDY3 && current_frame_flags_ &
|
| - ~PUSH_PROMISE_FLAG_END_PUSH_PROMISE) {
|
| + } else if (protocol_version() > SPDY3 &&
|
| + current_frame_flags_ &
|
| + ~(PUSH_PROMISE_FLAG_END_PUSH_PROMISE |
|
| + HEADERS_FLAG_PAD_LOW | HEADERS_FLAG_PAD_HIGH)) {
|
| set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
|
| }
|
| break;
|
| @@ -966,7 +970,9 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
|
| if (current_frame_length_ < GetContinuationMinimumSize() ||
|
| protocol_version() <= SPDY3) {
|
| set_error(SPDY_INVALID_CONTROL_FRAME);
|
| - } else if (current_frame_flags_ & ~HEADERS_FLAG_END_HEADERS) {
|
| + } else if (current_frame_flags_ &
|
| + ~(HEADERS_FLAG_END_HEADERS | HEADERS_FLAG_PAD_LOW |
|
| + HEADERS_FLAG_PAD_HIGH)) {
|
| set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
|
| }
|
| break;
|
| @@ -1444,7 +1450,7 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
|
| expect_continuation_ == 0);
|
| }
|
| }
|
| - CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
|
| + CHANGE_STATE(SPDY_READ_PADDING_LENGTH);
|
| break;
|
| case PUSH_PROMISE:
|
| {
|
| @@ -1475,7 +1481,7 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
|
| (current_frame_flags_ &
|
| PUSH_PROMISE_FLAG_END_PUSH_PROMISE) != 0);
|
| }
|
| - CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
|
| + CHANGE_STATE(SPDY_READ_PADDING_LENGTH);
|
| break;
|
| case CONTINUATION:
|
| {
|
| @@ -1501,7 +1507,7 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
|
| (current_frame_flags_ &
|
| HEADERS_FLAG_END_HEADERS) != 0);
|
| }
|
| - CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
|
| + CHANGE_STATE(SPDY_READ_PADDING_LENGTH);
|
| break;
|
| default:
|
| DCHECK(false);
|
| @@ -1527,7 +1533,8 @@ size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
|
| current_frame_type_ != CONTINUATION) {
|
| LOG(DFATAL) << "Unhandled frame type in ProcessControlFrameHeaderBlock.";
|
| }
|
| - size_t process_bytes = std::min(data_len, remaining_data_length_);
|
| + size_t process_bytes = std::min(
|
| + data_len, remaining_data_length_ - remaining_padding_payload_length_);
|
| if (is_hpack_header_block) {
|
| if (!GetHpackDecoder()->HandleControlFrameHeadersData(
|
| current_frame_stream_id_, data, process_bytes)) {
|
| @@ -1547,7 +1554,8 @@ size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
|
| remaining_data_length_ -= process_bytes;
|
|
|
| // Handle the case that there is no futher data in this frame.
|
| - if (remaining_data_length_ == 0 && processed_successfully) {
|
| + if (remaining_data_length_ == remaining_padding_payload_length_ &&
|
| + processed_successfully) {
|
| if (expect_continuation_ == 0) {
|
| if (is_hpack_header_block) {
|
| if (!GetHpackDecoder()->HandleControlFrameHeadersComplete(
|
| @@ -1567,14 +1575,10 @@ size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
|
| // OnControlFrameHeaderData() to indicate this.
|
| visitor_->OnControlFrameHeaderData(current_frame_stream_id_, NULL, 0);
|
| }
|
| - // If this is a FIN, tell the caller.
|
| - if ((current_frame_flags_ & CONTROL_FLAG_FIN) || end_stream_when_done_) {
|
| - end_stream_when_done_ = false;
|
| - visitor_->OnStreamFrameData(current_frame_stream_id_, NULL, 0, true);
|
| - }
|
| }
|
| - if (processed_successfully)
|
| - CHANGE_STATE(SPDY_AUTO_RESET);
|
| + if (processed_successfully) {
|
| + CHANGE_STATE(SPDY_CONSUME_PADDING);
|
| + }
|
| }
|
|
|
| // Handle error.
|
| @@ -1644,7 +1648,7 @@ size_t SpdyFramer::ProcessSettingsFramePayload(const char* data,
|
|
|
| void SpdyFramer::DeliverHpackBlockAsSpdy3Block() {
|
| DCHECK_LT(SPDY3, protocol_version());
|
| - DCHECK_EQ(0u, remaining_data_length_);
|
| + DCHECK_EQ(remaining_padding_payload_length_, remaining_data_length_);
|
|
|
| const SpdyNameValueBlock& block = GetHpackDecoder()->decoded_block();
|
| if (block.empty()) {
|
| @@ -1659,8 +1663,16 @@ void SpdyFramer::DeliverHpackBlockAsSpdy3Block() {
|
| SerializeNameValueBlockWithoutCompression(&builder, block);
|
| scoped_ptr<SpdyFrame> frame(builder.take());
|
|
|
| + // Preserve padding length, and reset it after the re-entrant call.
|
| + size_t remaining_padding = remaining_padding_payload_length_;
|
| +
|
| + remaining_padding_payload_length_ = 0;
|
| remaining_data_length_ = frame->size();
|
| +
|
| ProcessControlFrameHeaderBlock(frame->data(), frame->size(), false);
|
| +
|
| + remaining_padding_payload_length_ = remaining_padding;
|
| + remaining_data_length_ = remaining_padding;
|
| }
|
|
|
| bool SpdyFramer::ProcessSetting(const char* data) {
|
| @@ -2083,7 +2095,17 @@ size_t SpdyFramer::ProcessFramePaddingLength(const char* data, size_t len) {
|
| set_error(SPDY_INVALID_DATA_FRAME_FLAGS);
|
| return 0;
|
| }
|
| - CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
|
| + if (current_frame_type_ == DATA) {
|
| + CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
|
| + } else {
|
| + DCHECK(current_frame_type_ == HEADERS ||
|
| + current_frame_type_ == PUSH_PROMISE ||
|
| + current_frame_type_ == CONTINUATION ||
|
| + current_frame_type_ == SYN_STREAM ||
|
| + current_frame_type_ == SYN_REPLY)
|
| + << current_frame_type_;
|
| + CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
|
| + }
|
| }
|
| return original_len - len;
|
| }
|
| @@ -2095,10 +2117,10 @@ size_t SpdyFramer::ProcessFramePadding(const char* data, size_t 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) {
|
| + if (current_frame_type_ == DATA && amount_to_discard > 0) {
|
| + // 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.
|
| visitor_->OnStreamFrameData(
|
| current_frame_stream_id_, NULL, amount_to_discard, false);
|
| }
|
| @@ -2109,12 +2131,14 @@ size_t SpdyFramer::ProcessFramePadding(const char* data, size_t len) {
|
| }
|
|
|
| if (remaining_data_length_ == 0) {
|
| - // If the FIN flag is set, and there is no more data in this data frame,
|
| + // If the FIN flag is set, or this ends a header block which set FIN,
|
| // inform the visitor of EOF via a 0-length data frame.
|
| - if (current_frame_flags_ & DATA_FLAG_FIN) {
|
| + if (expect_continuation_ == 0 &&
|
| + ((current_frame_flags_ & CONTROL_FLAG_FIN) != 0 ||
|
| + end_stream_when_done_)) {
|
| + end_stream_when_done_ = false;
|
| visitor_->OnStreamFrameData(current_frame_stream_id_, NULL, 0, true);
|
| }
|
| -
|
| CHANGE_STATE(SPDY_AUTO_RESET);
|
| }
|
| return original_len - len;
|
|
|