| // 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 "quiche/http2/decoder/http2_structure_decoder.h" |
| |
| #include <algorithm> |
| #include <cstring> |
| |
| #include "quiche/common/platform/api/quiche_bug_tracker.h" |
| |
| namespace http2 { |
| |
| // Below we have some defensive coding: if we somehow run off the end, don't |
| // overwrite lots of memory. Note that most of this decoder is not defensive |
| // against bugs in the decoder, only against malicious encoders, but since |
| // we're copying memory into a buffer here, let's make sure we don't allow a |
| // small mistake to grow larger. The decoder will get stuck if we hit the |
| // QUICHE_BUG conditions, but shouldn't corrupt memory. |
| |
| uint32_t Http2StructureDecoder::IncompleteStart(DecodeBuffer* db, |
| uint32_t target_size) { |
| if (target_size > sizeof buffer_) { |
| QUICHE_BUG(http2_bug_154_1) |
| << "target_size too large for buffer: " << target_size; |
| return 0; |
| } |
| const uint32_t num_to_copy = db->MinLengthRemaining(target_size); |
| memcpy(buffer_, db->cursor(), num_to_copy); |
| offset_ = num_to_copy; |
| db->AdvanceCursor(num_to_copy); |
| return num_to_copy; |
| } |
| |
| DecodeStatus Http2StructureDecoder::IncompleteStart(DecodeBuffer* db, |
| uint32_t* remaining_payload, |
| uint32_t target_size) { |
| QUICHE_DVLOG(1) << "IncompleteStart@" << this |
| << ": *remaining_payload=" << *remaining_payload |
| << "; target_size=" << target_size |
| << "; db->Remaining=" << db->Remaining(); |
| *remaining_payload -= |
| IncompleteStart(db, std::min(target_size, *remaining_payload)); |
| if (*remaining_payload > 0 && db->Empty()) { |
| return DecodeStatus::kDecodeInProgress; |
| } |
| QUICHE_DVLOG(1) << "IncompleteStart: kDecodeError"; |
| return DecodeStatus::kDecodeError; |
| } |
| |
| bool Http2StructureDecoder::ResumeFillingBuffer(DecodeBuffer* db, |
| uint32_t target_size) { |
| QUICHE_DVLOG(2) << "ResumeFillingBuffer@" << this |
| << ": target_size=" << target_size << "; offset_=" << offset_ |
| << "; db->Remaining=" << db->Remaining(); |
| if (target_size < offset_) { |
| QUICHE_BUG(http2_bug_154_2) |
| << "Already filled buffer_! target_size=" << target_size |
| << " offset_=" << offset_; |
| return false; |
| } |
| const uint32_t needed = target_size - offset_; |
| const uint32_t num_to_copy = db->MinLengthRemaining(needed); |
| QUICHE_DVLOG(2) << "ResumeFillingBuffer num_to_copy=" << num_to_copy; |
| memcpy(&buffer_[offset_], db->cursor(), num_to_copy); |
| db->AdvanceCursor(num_to_copy); |
| offset_ += num_to_copy; |
| return needed == num_to_copy; |
| } |
| |
| bool Http2StructureDecoder::ResumeFillingBuffer(DecodeBuffer* db, |
| uint32_t* remaining_payload, |
| uint32_t target_size) { |
| QUICHE_DVLOG(2) << "ResumeFillingBuffer@" << this |
| << ": target_size=" << target_size << "; offset_=" << offset_ |
| << "; *remaining_payload=" << *remaining_payload |
| << "; db->Remaining=" << db->Remaining(); |
| if (target_size < offset_) { |
| QUICHE_BUG(http2_bug_154_3) |
| << "Already filled buffer_! target_size=" << target_size |
| << " offset_=" << offset_; |
| return false; |
| } |
| const uint32_t needed = target_size - offset_; |
| const uint32_t num_to_copy = |
| db->MinLengthRemaining(std::min(needed, *remaining_payload)); |
| QUICHE_DVLOG(2) << "ResumeFillingBuffer num_to_copy=" << num_to_copy; |
| memcpy(&buffer_[offset_], db->cursor(), num_to_copy); |
| db->AdvanceCursor(num_to_copy); |
| offset_ += num_to_copy; |
| *remaining_payload -= num_to_copy; |
| return needed == num_to_copy; |
| } |
| |
| } // namespace http2 |