1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/http2/decoder/http2_structure_decoder.h"
6
7 #include <algorithm>
8 #include <cstring>
9
10 #include "quiche/common/platform/api/quiche_bug_tracker.h"
11
12 namespace http2 {
13
14 // Below we have some defensive coding: if we somehow run off the end, don't
15 // overwrite lots of memory. Note that most of this decoder is not defensive
16 // against bugs in the decoder, only against malicious encoders, but since
17 // we're copying memory into a buffer here, let's make sure we don't allow a
18 // small mistake to grow larger. The decoder will get stuck if we hit the
19 // QUICHE_BUG conditions, but shouldn't corrupt memory.
20
IncompleteStart(DecodeBuffer * db,uint32_t target_size)21 uint32_t Http2StructureDecoder::IncompleteStart(DecodeBuffer* db,
22 uint32_t target_size) {
23 if (target_size > sizeof buffer_) {
24 QUICHE_BUG(http2_bug_154_1)
25 << "target_size too large for buffer: " << target_size;
26 return 0;
27 }
28 const uint32_t num_to_copy = db->MinLengthRemaining(target_size);
29 memcpy(buffer_, db->cursor(), num_to_copy);
30 offset_ = num_to_copy;
31 db->AdvanceCursor(num_to_copy);
32 return num_to_copy;
33 }
34
IncompleteStart(DecodeBuffer * db,uint32_t * remaining_payload,uint32_t target_size)35 DecodeStatus Http2StructureDecoder::IncompleteStart(DecodeBuffer* db,
36 uint32_t* remaining_payload,
37 uint32_t target_size) {
38 QUICHE_DVLOG(1) << "IncompleteStart@" << this
39 << ": *remaining_payload=" << *remaining_payload
40 << "; target_size=" << target_size
41 << "; db->Remaining=" << db->Remaining();
42 *remaining_payload -=
43 IncompleteStart(db, std::min(target_size, *remaining_payload));
44 if (*remaining_payload > 0 && db->Empty()) {
45 return DecodeStatus::kDecodeInProgress;
46 }
47 QUICHE_DVLOG(1) << "IncompleteStart: kDecodeError";
48 return DecodeStatus::kDecodeError;
49 }
50
ResumeFillingBuffer(DecodeBuffer * db,uint32_t target_size)51 bool Http2StructureDecoder::ResumeFillingBuffer(DecodeBuffer* db,
52 uint32_t target_size) {
53 QUICHE_DVLOG(2) << "ResumeFillingBuffer@" << this
54 << ": target_size=" << target_size << "; offset_=" << offset_
55 << "; db->Remaining=" << db->Remaining();
56 if (target_size < offset_) {
57 QUICHE_BUG(http2_bug_154_2)
58 << "Already filled buffer_! target_size=" << target_size
59 << " offset_=" << offset_;
60 return false;
61 }
62 const uint32_t needed = target_size - offset_;
63 const uint32_t num_to_copy = db->MinLengthRemaining(needed);
64 QUICHE_DVLOG(2) << "ResumeFillingBuffer num_to_copy=" << num_to_copy;
65 memcpy(&buffer_[offset_], db->cursor(), num_to_copy);
66 db->AdvanceCursor(num_to_copy);
67 offset_ += num_to_copy;
68 return needed == num_to_copy;
69 }
70
ResumeFillingBuffer(DecodeBuffer * db,uint32_t * remaining_payload,uint32_t target_size)71 bool Http2StructureDecoder::ResumeFillingBuffer(DecodeBuffer* db,
72 uint32_t* remaining_payload,
73 uint32_t target_size) {
74 QUICHE_DVLOG(2) << "ResumeFillingBuffer@" << this
75 << ": target_size=" << target_size << "; offset_=" << offset_
76 << "; *remaining_payload=" << *remaining_payload
77 << "; db->Remaining=" << db->Remaining();
78 if (target_size < offset_) {
79 QUICHE_BUG(http2_bug_154_3)
80 << "Already filled buffer_! target_size=" << target_size
81 << " offset_=" << offset_;
82 return false;
83 }
84 const uint32_t needed = target_size - offset_;
85 const uint32_t num_to_copy =
86 db->MinLengthRemaining(std::min(needed, *remaining_payload));
87 QUICHE_DVLOG(2) << "ResumeFillingBuffer num_to_copy=" << num_to_copy;
88 memcpy(&buffer_[offset_], db->cursor(), num_to_copy);
89 db->AdvanceCursor(num_to_copy);
90 offset_ += num_to_copy;
91 *remaining_payload -= num_to_copy;
92 return needed == num_to_copy;
93 }
94
95 } // namespace http2
96