xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/common/quiche_data_reader.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2020 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/common/quiche_data_reader.h"
6 
7 #include <cstring>
8 
9 #include "absl/strings/numbers.h"
10 #include "absl/strings/str_cat.h"
11 #include "absl/strings/string_view.h"
12 #include "quiche/common/platform/api/quiche_bug_tracker.h"
13 #include "quiche/common/platform/api/quiche_logging.h"
14 #include "quiche/common/quiche_endian.h"
15 
16 namespace quiche {
17 
QuicheDataReader(absl::string_view data)18 QuicheDataReader::QuicheDataReader(absl::string_view data)
19     : QuicheDataReader(data.data(), data.length(), quiche::NETWORK_BYTE_ORDER) {
20 }
21 
QuicheDataReader(const char * data,const size_t len)22 QuicheDataReader::QuicheDataReader(const char* data, const size_t len)
23     : QuicheDataReader(data, len, quiche::NETWORK_BYTE_ORDER) {}
24 
QuicheDataReader(const char * data,const size_t len,quiche::Endianness endianness)25 QuicheDataReader::QuicheDataReader(const char* data, const size_t len,
26                                    quiche::Endianness endianness)
27     : data_(data), len_(len), pos_(0), endianness_(endianness) {}
28 
ReadUInt8(uint8_t * result)29 bool QuicheDataReader::ReadUInt8(uint8_t* result) {
30   return ReadBytes(result, sizeof(*result));
31 }
32 
ReadUInt16(uint16_t * result)33 bool QuicheDataReader::ReadUInt16(uint16_t* result) {
34   if (!ReadBytes(result, sizeof(*result))) {
35     return false;
36   }
37   if (endianness_ == quiche::NETWORK_BYTE_ORDER) {
38     *result = quiche::QuicheEndian::NetToHost16(*result);
39   }
40   return true;
41 }
42 
ReadUInt24(uint32_t * result)43 bool QuicheDataReader::ReadUInt24(uint32_t* result) {
44   if (endianness_ != quiche::NETWORK_BYTE_ORDER) {
45     // TODO(b/214573190): Implement and test HOST_BYTE_ORDER case.
46     QUICHE_BUG(QuicheDataReader_ReadUInt24_NotImplemented);
47     return false;
48   }
49 
50   *result = 0;
51   if (!ReadBytes(reinterpret_cast<char*>(result) + 1, 3u)) {
52     return false;
53   }
54   *result = quiche::QuicheEndian::NetToHost32(*result);
55   return true;
56 }
57 
ReadUInt32(uint32_t * result)58 bool QuicheDataReader::ReadUInt32(uint32_t* result) {
59   if (!ReadBytes(result, sizeof(*result))) {
60     return false;
61   }
62   if (endianness_ == quiche::NETWORK_BYTE_ORDER) {
63     *result = quiche::QuicheEndian::NetToHost32(*result);
64   }
65   return true;
66 }
67 
ReadUInt64(uint64_t * result)68 bool QuicheDataReader::ReadUInt64(uint64_t* result) {
69   if (!ReadBytes(result, sizeof(*result))) {
70     return false;
71   }
72   if (endianness_ == quiche::NETWORK_BYTE_ORDER) {
73     *result = quiche::QuicheEndian::NetToHost64(*result);
74   }
75   return true;
76 }
77 
ReadBytesToUInt64(size_t num_bytes,uint64_t * result)78 bool QuicheDataReader::ReadBytesToUInt64(size_t num_bytes, uint64_t* result) {
79   *result = 0u;
80   if (num_bytes > sizeof(*result)) {
81     return false;
82   }
83   if (endianness_ == quiche::HOST_BYTE_ORDER) {
84     return ReadBytes(result, num_bytes);
85   }
86 
87   if (!ReadBytes(reinterpret_cast<char*>(result) + sizeof(*result) - num_bytes,
88                  num_bytes)) {
89     return false;
90   }
91   *result = quiche::QuicheEndian::NetToHost64(*result);
92   return true;
93 }
94 
ReadStringPiece16(absl::string_view * result)95 bool QuicheDataReader::ReadStringPiece16(absl::string_view* result) {
96   // Read resultant length.
97   uint16_t result_len;
98   if (!ReadUInt16(&result_len)) {
99     // OnFailure() already called.
100     return false;
101   }
102 
103   return ReadStringPiece(result, result_len);
104 }
105 
ReadStringPiece8(absl::string_view * result)106 bool QuicheDataReader::ReadStringPiece8(absl::string_view* result) {
107   // Read resultant length.
108   uint8_t result_len;
109   if (!ReadUInt8(&result_len)) {
110     // OnFailure() already called.
111     return false;
112   }
113 
114   return ReadStringPiece(result, result_len);
115 }
116 
ReadStringPiece(absl::string_view * result,size_t size)117 bool QuicheDataReader::ReadStringPiece(absl::string_view* result, size_t size) {
118   // Make sure that we have enough data to read.
119   if (!CanRead(size)) {
120     OnFailure();
121     return false;
122   }
123 
124   // Set result.
125   *result = absl::string_view(data_ + pos_, size);
126 
127   // Iterate.
128   pos_ += size;
129 
130   return true;
131 }
132 
ReadTag(uint32_t * tag)133 bool QuicheDataReader::ReadTag(uint32_t* tag) {
134   return ReadBytes(tag, sizeof(*tag));
135 }
136 
ReadDecimal64(size_t num_digits,uint64_t * result)137 bool QuicheDataReader::ReadDecimal64(size_t num_digits, uint64_t* result) {
138   absl::string_view digits;
139   if (!ReadStringPiece(&digits, num_digits)) {
140     return false;
141   }
142 
143   return absl::SimpleAtoi(digits, result);
144 }
145 
PeekVarInt62Length()146 QuicheVariableLengthIntegerLength QuicheDataReader::PeekVarInt62Length() {
147   QUICHE_DCHECK_EQ(endianness(), NETWORK_BYTE_ORDER);
148   const unsigned char* next =
149       reinterpret_cast<const unsigned char*>(data() + pos());
150   if (BytesRemaining() == 0) {
151     return VARIABLE_LENGTH_INTEGER_LENGTH_0;
152   }
153   return static_cast<QuicheVariableLengthIntegerLength>(
154       1 << ((*next & 0b11000000) >> 6));
155 }
156 
157 // Read an RFC 9000 62-bit Variable Length Integer.
158 //
159 // Performance notes
160 //
161 // Measurements and experiments showed that unrolling the four cases
162 // like this and dereferencing next_ as we do (*(next_+n) --- and then
163 // doing a single pos_+=x at the end) gains about 10% over making a
164 // loop and dereferencing next_ such as *(next_++)
165 //
166 // Using a register for pos_ was not helpful.
167 //
168 // Branches are ordered to increase the likelihood of the first being
169 // taken.
170 //
171 // Low-level optimization is useful here because this function will be
172 // called frequently, leading to outsize benefits.
ReadVarInt62(uint64_t * result)173 bool QuicheDataReader::ReadVarInt62(uint64_t* result) {
174   QUICHE_DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER);
175 
176   size_t remaining = BytesRemaining();
177   const unsigned char* next =
178       reinterpret_cast<const unsigned char*>(data() + pos());
179   if (remaining != 0) {
180     switch (*next & 0xc0) {
181       case 0xc0:
182         // Leading 0b11...... is 8 byte encoding
183         if (remaining >= 8) {
184           *result = (static_cast<uint64_t>((*(next)) & 0x3f) << 56) +
185                     (static_cast<uint64_t>(*(next + 1)) << 48) +
186                     (static_cast<uint64_t>(*(next + 2)) << 40) +
187                     (static_cast<uint64_t>(*(next + 3)) << 32) +
188                     (static_cast<uint64_t>(*(next + 4)) << 24) +
189                     (static_cast<uint64_t>(*(next + 5)) << 16) +
190                     (static_cast<uint64_t>(*(next + 6)) << 8) +
191                     (static_cast<uint64_t>(*(next + 7)) << 0);
192           AdvancePos(8);
193           return true;
194         }
195         return false;
196 
197       case 0x80:
198         // Leading 0b10...... is 4 byte encoding
199         if (remaining >= 4) {
200           *result = (((*(next)) & 0x3f) << 24) + (((*(next + 1)) << 16)) +
201                     (((*(next + 2)) << 8)) + (((*(next + 3)) << 0));
202           AdvancePos(4);
203           return true;
204         }
205         return false;
206 
207       case 0x40:
208         // Leading 0b01...... is 2 byte encoding
209         if (remaining >= 2) {
210           *result = (((*(next)) & 0x3f) << 8) + (*(next + 1));
211           AdvancePos(2);
212           return true;
213         }
214         return false;
215 
216       case 0x00:
217         // Leading 0b00...... is 1 byte encoding
218         *result = (*next) & 0x3f;
219         AdvancePos(1);
220         return true;
221     }
222   }
223   return false;
224 }
225 
ReadStringPieceVarInt62(absl::string_view * result)226 bool QuicheDataReader::ReadStringPieceVarInt62(absl::string_view* result) {
227   uint64_t result_length;
228   if (!ReadVarInt62(&result_length)) {
229     return false;
230   }
231   return ReadStringPiece(result, result_length);
232 }
233 
ReadStringVarInt62(std::string & result)234 bool QuicheDataReader::ReadStringVarInt62(std::string& result) {
235   absl::string_view result_view;
236   bool success = ReadStringPieceVarInt62(&result_view);
237   result = std::string(result_view);
238   return success;
239 }
240 
ReadRemainingPayload()241 absl::string_view QuicheDataReader::ReadRemainingPayload() {
242   absl::string_view payload = PeekRemainingPayload();
243   pos_ = len_;
244   return payload;
245 }
246 
PeekRemainingPayload() const247 absl::string_view QuicheDataReader::PeekRemainingPayload() const {
248   return absl::string_view(data_ + pos_, len_ - pos_);
249 }
250 
FullPayload() const251 absl::string_view QuicheDataReader::FullPayload() const {
252   return absl::string_view(data_, len_);
253 }
254 
PreviouslyReadPayload() const255 absl::string_view QuicheDataReader::PreviouslyReadPayload() const {
256   return absl::string_view(data_, pos_);
257 }
258 
ReadBytes(void * result,size_t size)259 bool QuicheDataReader::ReadBytes(void* result, size_t size) {
260   // Make sure that we have enough data to read.
261   if (!CanRead(size)) {
262     OnFailure();
263     return false;
264   }
265 
266   // Read into result.
267   memcpy(result, data_ + pos_, size);
268 
269   // Iterate.
270   pos_ += size;
271 
272   return true;
273 }
274 
Seek(size_t size)275 bool QuicheDataReader::Seek(size_t size) {
276   if (!CanRead(size)) {
277     OnFailure();
278     return false;
279   }
280   pos_ += size;
281   return true;
282 }
283 
IsDoneReading() const284 bool QuicheDataReader::IsDoneReading() const { return len_ == pos_; }
285 
BytesRemaining() const286 size_t QuicheDataReader::BytesRemaining() const {
287   if (pos_ > len_) {
288     QUICHE_BUG(quiche_reader_pos_out_of_bound)
289         << "QUIC reader pos out of bound: " << pos_ << ", len: " << len_;
290     return 0;
291   }
292   return len_ - pos_;
293 }
294 
TruncateRemaining(size_t truncation_length)295 bool QuicheDataReader::TruncateRemaining(size_t truncation_length) {
296   if (truncation_length > BytesRemaining()) {
297     return false;
298   }
299   len_ = pos_ + truncation_length;
300   return true;
301 }
302 
CanRead(size_t bytes) const303 bool QuicheDataReader::CanRead(size_t bytes) const {
304   return bytes <= (len_ - pos_);
305 }
306 
OnFailure()307 void QuicheDataReader::OnFailure() {
308   // Set our iterator to the end of the buffer so that further reads fail
309   // immediately.
310   pos_ = len_;
311 }
312 
PeekByte() const313 uint8_t QuicheDataReader::PeekByte() const {
314   if (pos_ >= len_) {
315     QUICHE_LOG(FATAL)
316         << "Reading is done, cannot peek next byte. Tried to read pos = "
317         << pos_ << " buffer length = " << len_;
318     return 0;
319   }
320   return data_[pos_];
321 }
322 
DebugString() const323 std::string QuicheDataReader::DebugString() const {
324   return absl::StrCat(" { length: ", len_, ", position: ", pos_, " }");
325 }
326 
327 #undef ENDPOINT  // undef for jumbo builds
328 }  // namespace quiche
329