xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/decoder/http2_structure_decoder.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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