| Index: net/spdy/spdy_framer.cc
|
| diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
|
| index 9d7ea876bb5164f9b397998db5fe54b4d07f5ade..fae97e8e3e53085e1c75d03da18a8f391d825d11 100644
|
| --- a/net/spdy/spdy_framer.cc
|
| +++ b/net/spdy/spdy_framer.cc
|
| @@ -70,6 +70,9 @@ const uint8 kNoFlags = 0;
|
| const size_t kPriorityDependencyPayloadSize = 4;
|
| const size_t kPriorityWeightPayloadSize = 1;
|
|
|
| +// Wire size of pad length field.
|
| +const size_t kPadLengthFieldSize = 1;
|
| +
|
| } // namespace
|
|
|
| const SpdyStreamId SpdyFramer::kInvalidStream = static_cast<SpdyStreamId>(-1);
|
| @@ -379,8 +382,8 @@ 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_READ_DATA_FRAME_PADDING_LENGTH:
|
| + return "SPDY_READ_DATA_FRAME_PADDING_LENGTH";
|
| case SPDY_CONSUME_PADDING:
|
| return "SPDY_CONSUME_PADDING";
|
| case SPDY_IGNORE_REMAINING_PAYLOAD:
|
| @@ -601,8 +604,8 @@ size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
|
| break;
|
| }
|
|
|
| - case SPDY_READ_PADDING_LENGTH: {
|
| - size_t bytes_read = ProcessFramePaddingLength(data, len);
|
| + case SPDY_READ_DATA_FRAME_PADDING_LENGTH: {
|
| + size_t bytes_read = ProcessDataFramePaddingLength(data, len);
|
| len -= bytes_read;
|
| data += bytes_read;
|
| break;
|
| @@ -809,7 +812,7 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
|
| remaining_data_length_,
|
| current_frame_flags_ & DATA_FLAG_FIN);
|
| if (remaining_data_length_ > 0) {
|
| - CHANGE_STATE(SPDY_READ_PADDING_LENGTH);
|
| + CHANGE_STATE(SPDY_READ_DATA_FRAME_PADDING_LENGTH);
|
| } else {
|
| // Empty data frame.
|
| if (current_frame_flags_ & DATA_FLAG_FIN) {
|
| @@ -1083,15 +1086,23 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
|
| break;
|
| case HEADERS:
|
| frame_size_without_variable_data = GetHeadersMinimumSize();
|
| - if (protocol_version() > SPDY3 &&
|
| - current_frame_flags_ & HEADERS_FLAG_PRIORITY) {
|
| + if (protocol_version() > SPDY3) {
|
| + if (current_frame_flags_ & HEADERS_FLAG_PADDED) {
|
| + frame_size_without_variable_data += kPadLengthFieldSize;
|
| + }
|
| + if (current_frame_flags_ & HEADERS_FLAG_PRIORITY) {
|
| frame_size_without_variable_data +=
|
| kPriorityDependencyPayloadSize +
|
| kPriorityWeightPayloadSize;
|
| + }
|
| }
|
| break;
|
| case PUSH_PROMISE:
|
| frame_size_without_variable_data = GetPushPromiseMinimumSize();
|
| + if (protocol_version() > SPDY3 &&
|
| + current_frame_flags_ & PUSH_PROMISE_FLAG_PADDED) {
|
| + frame_size_without_variable_data += kPadLengthFieldSize;
|
| + }
|
| break;
|
| case CONTINUATION:
|
| frame_size_without_variable_data = GetContinuationMinimumSize();
|
| @@ -1457,6 +1468,14 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
|
| expect_continuation_ = current_frame_stream_id_;
|
| end_stream_when_done_ = current_frame_flags_ & CONTROL_FLAG_FIN;
|
| }
|
| + if (protocol_version() > SPDY3 &&
|
| + current_frame_flags_ & HEADERS_FLAG_PADDED) {
|
| + uint8 pad_payload_len = 0;
|
| + DCHECK_EQ(remaining_padding_payload_length_, 0u);
|
| + successful_read = reader.ReadUInt8(&pad_payload_len);
|
| + DCHECK(successful_read);
|
| + remaining_padding_payload_length_ = pad_payload_len;
|
| + }
|
| const bool has_priority =
|
| (current_frame_flags_ & HEADERS_FLAG_PRIORITY) != 0;
|
| uint32 priority = 0;
|
| @@ -1502,7 +1521,7 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
|
| expect_continuation_ == 0);
|
| }
|
| }
|
| - CHANGE_STATE(SPDY_READ_PADDING_LENGTH);
|
| + CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
|
| break;
|
| case PUSH_PROMISE:
|
| {
|
| @@ -1511,6 +1530,17 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
|
| set_error(SPDY_INVALID_CONTROL_FRAME);
|
| break;
|
| }
|
| + bool successful_read = true;
|
| + if (protocol_version() > SPDY3 &&
|
| + current_frame_flags_ & PUSH_PROMISE_FLAG_PADDED) {
|
| + DCHECK_EQ(remaining_padding_payload_length_, 0u);
|
| + uint8 pad_payload_len = 0;
|
| + successful_read = reader.ReadUInt8(&pad_payload_len);
|
| + DCHECK(successful_read);
|
| + remaining_padding_payload_length_ = pad_payload_len;
|
| + }
|
| + }
|
| + {
|
| SpdyStreamId promised_stream_id = kInvalidStream;
|
| bool successful_read = reader.ReadUInt31(&promised_stream_id);
|
| DCHECK(successful_read);
|
| @@ -1533,7 +1563,7 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
|
| (current_frame_flags_ &
|
| PUSH_PROMISE_FLAG_END_PUSH_PROMISE) != 0);
|
| }
|
| - CHANGE_STATE(SPDY_READ_PADDING_LENGTH);
|
| + CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
|
| break;
|
| case CONTINUATION:
|
| {
|
| @@ -2120,11 +2150,10 @@ size_t SpdyFramer::ProcessAltSvcFramePayload(const char* data, size_t len) {
|
| return processed_bytes;
|
| }
|
|
|
| -// TODO(raullenchai): ProcessFramePaddingLength should be able to deal with
|
| -// HEADERS_FLAG_PADDED and PUSH_PROMISE_FLAG_PADDED as well (see b/15777051).
|
| -size_t SpdyFramer::ProcessFramePaddingLength(const char* data, size_t len) {
|
| - DCHECK_EQ(SPDY_READ_PADDING_LENGTH, state_);
|
| - DCHECK_EQ(remaining_padding_payload_length_, 0u);
|
| +size_t SpdyFramer::ProcessDataFramePaddingLength(const char* data, size_t len) {
|
| + DCHECK_EQ(SPDY_READ_DATA_FRAME_PADDING_LENGTH, state_);
|
| + DCHECK_EQ(0u, remaining_padding_payload_length_);
|
| + DCHECK_EQ(DATA, current_frame_type_);
|
|
|
| size_t original_len = len;
|
| if (current_frame_flags_ & DATA_FLAG_PADDED) {
|
| @@ -2149,16 +2178,7 @@ size_t SpdyFramer::ProcessFramePaddingLength(const char* data, size_t len) {
|
| set_error(SPDY_INVALID_DATA_FRAME_FLAGS);
|
| return 0;
|
| }
|
| - 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_ == SYN_STREAM ||
|
| - current_frame_type_ == SYN_REPLY)
|
| - << current_frame_type_;
|
| - CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
|
| - }
|
| + CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
|
| return original_len - len;
|
| }
|
|
|
| @@ -2606,11 +2626,20 @@ SpdySerializedFrame* SpdyFramer::SerializeHeaders(
|
| if (headers.has_priority()) {
|
| flags |= HEADERS_FLAG_PRIORITY;
|
| }
|
| + if (headers.padded()) {
|
| + flags |= HEADERS_FLAG_PADDED;
|
| + }
|
| }
|
|
|
| - // The size of this frame, including variable-length name-value block.
|
| + // The size of this frame, including padding (if there is any)
|
| + // and variable-length name-value block.
|
| size_t size = GetHeadersMinimumSize();
|
|
|
| + if (protocol_version() > SPDY3 && headers.padded()) {
|
| + size += kPadLengthFieldSize;
|
| + size += headers.padding_payload_len();
|
| + }
|
| +
|
| uint32 priority = headers.priority();
|
| if (headers.has_priority()) {
|
| if (priority > GetLowestPriority()) {
|
| @@ -2655,6 +2684,11 @@ SpdySerializedFrame* SpdyFramer::SerializeHeaders(
|
| DCHECK_EQ(GetHeadersMinimumSize(), builder.length());
|
|
|
| if (protocol_version() > SPDY3) {
|
| + int padding_payload_len = 0;
|
| + if (headers.padded()) {
|
| + builder.WriteUInt8(headers.padding_payload_len());
|
| + padding_payload_len = headers.padding_payload_len();
|
| + }
|
| if (headers.has_priority()) {
|
| // TODO(jgraettinger): Plumb priorities and stream dependencies.
|
| builder.WriteUInt32(0); // Non-exclusive bit and root stream ID.
|
| @@ -2663,7 +2697,8 @@ SpdySerializedFrame* SpdyFramer::SerializeHeaders(
|
| WritePayloadWithContinuation(&builder,
|
| hpack_encoding,
|
| headers.stream_id(),
|
| - HEADERS);
|
| + HEADERS,
|
| + padding_payload_len);
|
| } else {
|
| SerializeNameValueBlock(&builder, headers);
|
| }
|
| @@ -2717,6 +2752,12 @@ SpdyFrame* SpdyFramer::SerializePushPromise(
|
| // The size of this frame, including variable-length name-value block.
|
| size_t size = GetPushPromiseMinimumSize();
|
|
|
| + if (push_promise.padded()) {
|
| + flags |= PUSH_PROMISE_FLAG_PADDED;
|
| + size += kPadLengthFieldSize;
|
| + size += push_promise.padding_payload_len();
|
| + }
|
| +
|
| string hpack_encoding;
|
| if (enable_compression_) {
|
| GetHpackEncoder()->EncodeHeaderSet(
|
| @@ -2737,13 +2778,24 @@ SpdyFrame* SpdyFramer::SerializePushPromise(
|
| PUSH_PROMISE,
|
| flags,
|
| push_promise.stream_id());
|
| - builder.WriteUInt32(push_promise.promised_stream_id());
|
| - DCHECK_EQ(GetPushPromiseMinimumSize(), builder.length());
|
| + int padding_payload_len = 0;
|
| + if (push_promise.padded()) {
|
| + builder.WriteUInt8(push_promise.padding_payload_len());
|
| + builder.WriteUInt32(push_promise.promised_stream_id());
|
| + DCHECK_EQ(GetPushPromiseMinimumSize() + kPadLengthFieldSize,
|
| + builder.length());
|
| +
|
| + padding_payload_len = push_promise.padding_payload_len();
|
| + } else {
|
| + builder.WriteUInt32(push_promise.promised_stream_id());
|
| + DCHECK_EQ(GetPushPromiseMinimumSize(), builder.length());
|
| + }
|
|
|
| WritePayloadWithContinuation(&builder,
|
| hpack_encoding,
|
| push_promise.stream_id(),
|
| - PUSH_PROMISE);
|
| + PUSH_PROMISE,
|
| + padding_payload_len);
|
|
|
| if (debug_visitor_) {
|
| // SPDY4 uses HPACK for header compression. However, continue to
|
| @@ -2923,32 +2975,34 @@ size_t SpdyFramer::GetNumberRequiredContinuationFrames(size_t size) {
|
| void SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder,
|
| const string& hpack_encoding,
|
| SpdyStreamId stream_id,
|
| - SpdyFrameType type) {
|
| + SpdyFrameType type,
|
| + int padding_payload_len) {
|
| const size_t kMaxControlFrameSize = GetHeaderFragmentMaxSize();
|
|
|
| - // In addition to the prefix, fixed_field_size includes the size of
|
| - // any fields that come before the variable-length name/value block.
|
| - size_t fixed_field_size = 0;
|
| uint8 end_flag = 0;
|
| uint8 flags = 0;
|
| if (type == HEADERS) {
|
| - fixed_field_size = GetHeadersMinimumSize();
|
| end_flag = HEADERS_FLAG_END_HEADERS;
|
| } else if (type == PUSH_PROMISE) {
|
| - fixed_field_size = GetPushPromiseMinimumSize();
|
| end_flag = PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
|
| } else {
|
| DLOG(FATAL) << "CONTINUATION frames cannot be used with frame type "
|
| << FrameTypeToString(type);
|
| }
|
|
|
| - // Write as much of the payload as possible into the initial frame.
|
| - size_t bytes_remaining = hpack_encoding.size() -
|
| - std::min(hpack_encoding.size(),
|
| - kMaxControlFrameSize - fixed_field_size);
|
| + // Write all the padding payload and as much of the data payload as possible
|
| + // into the initial frame.
|
| + size_t bytes_remaining = 0;
|
| + bytes_remaining = hpack_encoding.size() -
|
| + std::min(hpack_encoding.size(),
|
| + kMaxControlFrameSize - builder->length() -
|
| + padding_payload_len);
|
| builder->WriteBytes(&hpack_encoding[0],
|
| hpack_encoding.size() - bytes_remaining);
|
| -
|
| + if (padding_payload_len > 0) {
|
| + string padding = string(padding_payload_len, 0);
|
| + builder->WriteBytes(padding.data(), padding.length());
|
| + }
|
| if (bytes_remaining > 0) {
|
| builder->OverwriteLength(*this,
|
| kMaxControlFrameSize - GetControlFrameHeaderSize());
|
|
|