| Index: net/spdy/spdy_framer.cc
|
| diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
|
| index 80cfbd06886626ba78aa45fca39ccffca79c490d..3400ddd002ccff9f2d5c5b483b56cfa2cc4239e8 100644
|
| --- a/net/spdy/spdy_framer.cc
|
| +++ b/net/spdy/spdy_framer.cc
|
| @@ -179,8 +179,8 @@ size_t SpdyFramer::GetSynStreamMinimumSize() const {
|
| return GetControlFrameHeaderSize() + 10;
|
| } else {
|
| // Calculated as:
|
| - // frame prefix + 4 (associated stream ID) + 1 (priority) + 1 (slot)
|
| - return GetControlFrameHeaderSize() + 6;
|
| + // frame prefix + 4 (priority)
|
| + return GetControlFrameHeaderSize() + 4;
|
| }
|
| }
|
|
|
| @@ -683,6 +683,7 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
|
| // Do some sanity checking on the control frame sizes and flags.
|
| switch (current_frame_type_) {
|
| case SYN_STREAM:
|
| + DCHECK_GT(4, spdy_version_);
|
| if (current_frame_length_ < GetSynStreamMinimumSize()) {
|
| set_error(SPDY_INVALID_CONTROL_FRAME);
|
| } else if (current_frame_flags_ &
|
| @@ -734,10 +735,21 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
|
| break;
|
| }
|
| case HEADERS:
|
| - 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);
|
| + {
|
| + size_t min_size = GetHeadersMinimumSize();
|
| + if (spdy_version_ > 3 &&
|
| + (current_frame_flags_ & HEADERS_FLAG_PRIORITY)) {
|
| + min_size += 4;
|
| + }
|
| + if (current_frame_length_ < min_size) {
|
| + set_error(SPDY_INVALID_CONTROL_FRAME);
|
| + } else if (spdy_version_ < 4 &&
|
| + current_frame_flags_ & ~CONTROL_FLAG_FIN) {
|
| + set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
|
| + } else if (spdy_version_ > 3 && current_frame_flags_ &
|
| + ~(CONTROL_FLAG_FIN | HEADERS_FLAG_PRIORITY)) {
|
| + set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
|
| + }
|
| }
|
| break;
|
| case WINDOW_UPDATE:
|
| @@ -815,6 +827,9 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
|
| break;
|
| case HEADERS:
|
| frame_size_without_variable_data = GetHeadersMinimumSize();
|
| + if (spdy_version_ > 3 && current_frame_flags_ & HEADERS_FLAG_PRIORITY) {
|
| + frame_size_without_variable_data += 4; // priority
|
| + }
|
| break;
|
| case PUSH_PROMISE:
|
| frame_size_without_variable_data = GetPushPromiseMinimumSize();
|
| @@ -1077,7 +1092,7 @@ void SpdyFramer::WriteHeaderBlockToZ(const SpdyHeaderBlock* headers,
|
| size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
|
| size_t len) {
|
| DCHECK_EQ(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK, state_);
|
| - size_t original_len = len;
|
| + const size_t original_len = len;
|
|
|
| if (remaining_control_header_ > 0) {
|
| size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
|
| @@ -1094,6 +1109,7 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
|
| switch (current_frame_type_) {
|
| case SYN_STREAM:
|
| {
|
| + DCHECK_GT(4, spdy_version_);
|
| bool successful_read = true;
|
| if (spdy_version_ < 4) {
|
| successful_read = reader.ReadUInt31(¤t_frame_stream_id_);
|
| @@ -1152,6 +1168,9 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
|
| case HEADERS:
|
| // SYN_REPLY and HEADERS are the same, save for the visitor call.
|
| {
|
| + if (spdy_version_ > 3) {
|
| + DCHECK_EQ(HEADERS, current_frame_type_);
|
| + }
|
| bool successful_read = true;
|
| if (spdy_version_ < 4) {
|
| successful_read = reader.ReadUInt31(¤t_frame_stream_id_);
|
| @@ -1165,17 +1184,40 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
|
| // SPDY 2 had two unused bytes here. Seek past them.
|
| reader.Seek(2);
|
| }
|
| + const bool has_priority =
|
| + (current_frame_flags_ & HEADERS_FLAG_PRIORITY) != 0;
|
| + uint32 priority = 0;
|
| + if (protocol_version() > 3 && has_priority) {
|
| + successful_read = reader.ReadUInt31(&priority);
|
| + DCHECK(successful_read);
|
| + }
|
| DCHECK(reader.IsDoneReading());
|
| if (debug_visitor_) {
|
| + // SPDY 4 reports HEADERS with PRIORITY as SYN_STREAM.
|
| + SpdyFrameType reported_type = current_frame_type_;
|
| + if (protocol_version() > 3 && has_priority) {
|
| + reported_type = SYN_STREAM;
|
| + }
|
| debug_visitor_->OnReceiveCompressedFrame(
|
| current_frame_stream_id_,
|
| - current_frame_type_,
|
| + reported_type,
|
| current_frame_length_);
|
| }
|
| if (current_frame_type_ == SYN_REPLY) {
|
| visitor_->OnSynReply(
|
| current_frame_stream_id_,
|
| (current_frame_flags_ & CONTROL_FLAG_FIN) != 0);
|
| + } else if (spdy_version_ > 3 &&
|
| + current_frame_flags_ & HEADERS_FLAG_PRIORITY) {
|
| + // SPDY 4+ is missing SYN_STREAM. Simulate it so that API changes
|
| + // can be made independent of wire changes.
|
| + visitor_->OnSynStream(
|
| + current_frame_stream_id_,
|
| + 0, // associated_to_stream_id
|
| + priority,
|
| + 0, // TODO(hkhalil): handle slot for SPDY 4+?
|
| + current_frame_flags_ & CONTROL_FLAG_FIN,
|
| + false); // unidirectional
|
| } else {
|
| visitor_->OnHeaders(
|
| current_frame_stream_id_,
|
| @@ -1663,8 +1705,19 @@ SpdySerializedFrame* SpdyFramer::SerializeSynStream(
|
| flags |= CONTROL_FLAG_FIN;
|
| }
|
| if (syn_stream.unidirectional()) {
|
| + // TODO(hkhalil): invalid for HTTP2.
|
| flags |= CONTROL_FLAG_UNIDIRECTIONAL;
|
| }
|
| + if (spdy_version_ >= 4) {
|
| + flags |= HEADERS_FLAG_PRIORITY;
|
| + }
|
| +
|
| + // Sanitize priority.
|
| + uint8 priority = syn_stream.priority();
|
| + if (priority > GetLowestPriority()) {
|
| + DLOG(DFATAL) << "Priority out-of-bounds.";
|
| + priority = GetLowestPriority();
|
| + }
|
|
|
| // The size of this frame, including variable-length name-value block.
|
| const size_t size = GetSynStreamMinimumSize()
|
| @@ -1674,26 +1727,23 @@ SpdySerializedFrame* SpdyFramer::SerializeSynStream(
|
| if (spdy_version_ < 4) {
|
| builder.WriteControlFrameHeader(*this, SYN_STREAM, flags);
|
| builder.WriteUInt32(syn_stream.stream_id());
|
| + builder.WriteUInt32(syn_stream.associated_to_stream_id());
|
| + builder.WriteUInt8(priority << ((spdy_version_ < 3) ? 6 : 5));
|
| + builder.WriteUInt8(syn_stream.slot());
|
| } else {
|
| builder.WriteFramePrefix(*this,
|
| - SYN_STREAM,
|
| + HEADERS,
|
| flags,
|
| syn_stream.stream_id());
|
| + builder.WriteUInt32(priority);
|
| }
|
| - builder.WriteUInt32(syn_stream.associated_to_stream_id());
|
| - uint8 priority = syn_stream.priority();
|
| - if (priority > GetLowestPriority()) {
|
| - DLOG(DFATAL) << "Priority out-of-bounds.";
|
| - priority = GetLowestPriority();
|
| - }
|
| - builder.WriteUInt8(priority << ((spdy_version_ < 3) ? 6 : 5));
|
| - builder.WriteUInt8(syn_stream.slot());
|
| DCHECK_EQ(GetSynStreamMinimumSize(), builder.length());
|
| SerializeNameValueBlock(&builder, syn_stream);
|
|
|
| if (debug_visitor_) {
|
| const size_t payload_len = GetSerializedLength(
|
| protocol_version(), &(syn_stream.name_value_block()));
|
| + // SPDY 4 reports this compression as a SYN_STREAM compression.
|
| debug_visitor_->OnSendCompressedFrame(syn_stream.stream_id(),
|
| SYN_STREAM,
|
| payload_len,
|
| @@ -1734,7 +1784,7 @@ SpdySerializedFrame* SpdyFramer::SerializeSynReply(
|
| builder.WriteUInt32(syn_reply.stream_id());
|
| } else {
|
| builder.WriteFramePrefix(*this,
|
| - SYN_REPLY,
|
| + HEADERS,
|
| flags,
|
| syn_reply.stream_id());
|
| }
|
|
|