|  | // Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "http2/decoder/frame_decoder_state.h" | 
|  |  | 
|  | namespace http2 { | 
|  |  | 
|  | DecodeStatus FrameDecoderState::ReadPadLength(DecodeBuffer* db, | 
|  | bool report_pad_length) { | 
|  | HTTP2_DVLOG(2) << "ReadPadLength db->Remaining=" << db->Remaining() | 
|  | << "; payload_length=" << frame_header().payload_length; | 
|  | QUICHE_DCHECK(IsPaddable()); | 
|  | QUICHE_DCHECK(frame_header().IsPadded()); | 
|  |  | 
|  | // Pad Length is always at the start of the frame, so remaining_payload_ | 
|  | // should equal payload_length at this point. | 
|  | const uint32_t total_payload = frame_header().payload_length; | 
|  | QUICHE_DCHECK_EQ(total_payload, remaining_payload_); | 
|  | QUICHE_DCHECK_EQ(0u, remaining_padding_); | 
|  |  | 
|  | if (db->HasData()) { | 
|  | const uint32_t pad_length = db->DecodeUInt8(); | 
|  | const uint32_t total_padding = pad_length + 1; | 
|  | if (total_padding <= total_payload) { | 
|  | remaining_padding_ = pad_length; | 
|  | remaining_payload_ = total_payload - total_padding; | 
|  | if (report_pad_length) { | 
|  | listener()->OnPadLength(pad_length); | 
|  | } | 
|  | return DecodeStatus::kDecodeDone; | 
|  | } | 
|  | const uint32_t missing_length = total_padding - total_payload; | 
|  | // To allow for the possibility of recovery, record the number of | 
|  | // remaining bytes of the frame's payload (invalid though it is) | 
|  | // in remaining_payload_. | 
|  | remaining_payload_ = total_payload - 1;  // 1 for sizeof(Pad Length). | 
|  | remaining_padding_ = 0; | 
|  | listener()->OnPaddingTooLong(frame_header(), missing_length); | 
|  | return DecodeStatus::kDecodeError; | 
|  | } | 
|  |  | 
|  | if (total_payload == 0) { | 
|  | remaining_payload_ = 0; | 
|  | remaining_padding_ = 0; | 
|  | listener()->OnPaddingTooLong(frame_header(), 1); | 
|  | return DecodeStatus::kDecodeError; | 
|  | } | 
|  | // Need to wait for another buffer. | 
|  | return DecodeStatus::kDecodeInProgress; | 
|  | } | 
|  |  | 
|  | bool FrameDecoderState::SkipPadding(DecodeBuffer* db) { | 
|  | HTTP2_DVLOG(2) << "SkipPadding remaining_padding_=" << remaining_padding_ | 
|  | << ", db->Remaining=" << db->Remaining() | 
|  | << ", header: " << frame_header(); | 
|  | QUICHE_DCHECK_EQ(remaining_payload_, 0u); | 
|  | QUICHE_DCHECK(IsPaddable()) << "header: " << frame_header(); | 
|  | QUICHE_DCHECK(remaining_padding_ == 0 || frame_header().IsPadded()) | 
|  | << "remaining_padding_=" << remaining_padding_ | 
|  | << ", header: " << frame_header(); | 
|  | const size_t avail = AvailablePadding(db); | 
|  | if (avail > 0) { | 
|  | listener()->OnPadding(db->cursor(), avail); | 
|  | db->AdvanceCursor(avail); | 
|  | remaining_padding_ -= avail; | 
|  | } | 
|  | return remaining_padding_ == 0; | 
|  | } | 
|  |  | 
|  | DecodeStatus FrameDecoderState::ReportFrameSizeError() { | 
|  | HTTP2_DVLOG(2) << "FrameDecoderState::ReportFrameSizeError: " | 
|  | << " remaining_payload_=" << remaining_payload_ | 
|  | << "; remaining_padding_=" << remaining_padding_ | 
|  | << ", header: " << frame_header(); | 
|  | listener()->OnFrameSizeError(frame_header()); | 
|  | return DecodeStatus::kDecodeError; | 
|  | } | 
|  |  | 
|  | }  // namespace http2 |