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