OLD | NEW |
| (Empty) |
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 #ifndef NET_HTTP2_DECODER_DECODE_BUFFER_H_ | |
6 #define NET_HTTP2_DECODER_DECODE_BUFFER_H_ | |
7 | |
8 // DecodeBuffer provides primitives for decoding various integer types found | |
9 // in HTTP/2 frames. | |
10 // DecodeBuffer wraps a byte array from which we can read and decode serialized | |
11 // HTTP/2 frames, or parts thereof. DecodeBuffer is intended only for stack | |
12 // allocation, where the caller is typically going to use the DecodeBuffer | |
13 // instance as part of decoding the entire buffer before returning to its own | |
14 // caller. Only the concrete Slow* methods are defined in the cc file, | |
15 // all other methods are defined in this header file to enable inlining. | |
16 | |
17 #include <stddef.h> | |
18 #include <stdint.h> | |
19 | |
20 #include <algorithm> | |
21 | |
22 #include "base/logging.h" | |
23 #include "base/macros.h" | |
24 #include "base/strings/string_piece.h" | |
25 #include "net/base/net_export.h" | |
26 | |
27 namespace net { | |
28 class DecodeBufferSubset; | |
29 | |
30 class NET_EXPORT_PRIVATE DecodeBuffer { | |
31 public: | |
32 DecodeBuffer(const char* buffer, size_t len) | |
33 : buffer_(buffer), cursor_(buffer), beyond_(buffer + len) { | |
34 DCHECK_NE(buffer, nullptr); | |
35 DCHECK_LE(len, MaxDecodeBufferLength()); | |
36 } | |
37 explicit DecodeBuffer(base::StringPiece s) | |
38 : DecodeBuffer(s.data(), s.size()) {} | |
39 // Constructor for character arrays, typically in tests. For example: | |
40 // const char input[] = { 0x11 }; | |
41 // DecodeBuffer b(input); | |
42 template <size_t N> | |
43 explicit DecodeBuffer(const char (&buf)[N]) : DecodeBuffer(buf, N) {} | |
44 | |
45 bool Empty() const { return cursor_ >= beyond_; } | |
46 bool HasData() const { return cursor_ < beyond_; } | |
47 size_t Remaining() const { | |
48 DCHECK_LE(cursor_, beyond_); | |
49 return beyond_ - cursor_; | |
50 } | |
51 size_t Offset() const { return cursor_ - buffer_; } | |
52 size_t FullSize() const { return beyond_ - buffer_; } | |
53 | |
54 // Returns the minimum of the number of bytes remaining in this DecodeBuffer | |
55 // and |length|, in support of determining how much of some structure/payload | |
56 // is in this DecodeBuffer. | |
57 size_t MinLengthRemaining(size_t length) const { | |
58 return std::min(length, Remaining()); | |
59 } | |
60 | |
61 // For string decoding, returns a pointer to the next byte/char to be decoded. | |
62 const char* cursor() const { return cursor_; } | |
63 // Advances the cursor (pointer to the next byte/char to be decoded). | |
64 void AdvanceCursor(size_t amount) { | |
65 DCHECK_LE(amount, Remaining()); // Need at least that much remaining. | |
66 DCHECK_EQ(subset_, nullptr) << "Access via subset only when present."; | |
67 cursor_ += amount; | |
68 } | |
69 | |
70 // Only call methods starting "Decode" when there is enough input remaining. | |
71 char DecodeChar() { | |
72 DCHECK_LE(1u, Remaining()); // Need at least one byte remaining. | |
73 DCHECK_EQ(subset_, nullptr) << "Access via subset only when present."; | |
74 return *cursor_++; | |
75 } | |
76 | |
77 uint8_t DecodeUInt8() { return static_cast<uint8_t>(DecodeChar()); } | |
78 | |
79 uint16_t DecodeUInt16() { | |
80 DCHECK_LE(2u, Remaining()); | |
81 const uint8_t b1 = DecodeUInt8(); | |
82 const uint8_t b2 = DecodeUInt8(); | |
83 // Note that chars are automatically promoted to ints during arithmetic, | |
84 // so the b1 << 8 doesn't end up as zero before being or-ed with b2. | |
85 // And the left-shift operator has higher precedence than the or operator. | |
86 return b1 << 8 | b2; | |
87 } | |
88 | |
89 uint32_t DecodeUInt24() { | |
90 DCHECK_LE(3u, Remaining()); | |
91 const uint8_t b1 = DecodeUInt8(); | |
92 const uint8_t b2 = DecodeUInt8(); | |
93 const uint8_t b3 = DecodeUInt8(); | |
94 return b1 << 16 | b2 << 8 | b3; | |
95 } | |
96 | |
97 // For 31-bit unsigned integers, where the 32nd bit is reserved for future | |
98 // use (i.e. the high-bit of the first byte of the encoding); examples: | |
99 // the Stream Id in a frame header or the Window Size Increment in a | |
100 // WINDOW_UPDATE frame. | |
101 uint32_t DecodeUInt31() { | |
102 DCHECK_LE(4u, Remaining()); | |
103 const uint8_t b1 = DecodeUInt8() & 0x7f; // Mask out the high order bit. | |
104 const uint8_t b2 = DecodeUInt8(); | |
105 const uint8_t b3 = DecodeUInt8(); | |
106 const uint8_t b4 = DecodeUInt8(); | |
107 return b1 << 24 | b2 << 16 | b3 << 8 | b4; | |
108 } | |
109 | |
110 uint32_t DecodeUInt32() { | |
111 DCHECK_LE(4u, Remaining()); | |
112 const uint8_t b1 = DecodeUInt8(); | |
113 const uint8_t b2 = DecodeUInt8(); | |
114 const uint8_t b3 = DecodeUInt8(); | |
115 const uint8_t b4 = DecodeUInt8(); | |
116 return b1 << 24 | b2 << 16 | b3 << 8 | b4; | |
117 } | |
118 | |
119 // SlowDecode* routines are used for decoding a multi-field structure when | |
120 // there may not be enough bytes in the buffer to decode the entirety of the | |
121 // structure. | |
122 | |
123 // Read as much of an unsigned int field of an encoded structure as possible, | |
124 // keeping track via decode_offset of our position in the encoded structure. | |
125 // Returns true if the field has been fully decoded. | |
126 // |field_size| is the number of bytes of the encoding of the field (usually | |
127 // a compile time fixed value). | |
128 // |field_offset| is the offset of the first byte of the encoding of the field | |
129 // within the encoding of that structure (usually a compile time fixed value). | |
130 // |*decode_offset| is the offset of the byte to be decoded next. | |
131 // |*value| is the storage for the decoded value, and is used for storing | |
132 // partially decoded values; if some, but not all, bytes of the encoding are | |
133 // available then this method will return having stored the decoded bytes into | |
134 // *value. | |
135 bool SlowDecodeUnsignedInt(uint32_t field_size, | |
136 uint32_t field_offset, | |
137 uint32_t* decode_offset, | |
138 uint32_t* value); | |
139 | |
140 // Like SlowDecodeUnsignedInt, but specifically for 8-bit unsigned integers. | |
141 // Obviously a byte can't be split (on our byte addressable machines), but | |
142 // a larger structure containing such a field might be. | |
143 bool SlowDecodeUInt8(uint32_t field_offset, | |
144 uint32_t* decode_offset, | |
145 uint8_t* value); | |
146 | |
147 // Like SlowDecodeUnsignedInt, but specifically for 16-bit unsigned integers. | |
148 bool SlowDecodeUInt16(uint32_t field_offset, | |
149 uint32_t* decode_offset, | |
150 uint16_t* value); | |
151 | |
152 // Like SlowDecodeUnsignedInt, but specifically for 24-bit unsigned integers. | |
153 bool SlowDecodeUInt24(uint32_t field_offset, | |
154 uint32_t* decode_offset, | |
155 uint32_t* value); | |
156 | |
157 // Like SlowDecodeUnsignedInt, but specifically for 31-bit unsigned integers. | |
158 // (same definition as for DecodeUInt31). | |
159 bool SlowDecodeUInt31(uint32_t field_offset, | |
160 uint32_t* decode_offset, | |
161 uint32_t* value); | |
162 | |
163 // Like SlowDecodeUnsignedInt, but specifically for 31-bit unsigned integers. | |
164 bool SlowDecodeUInt32(uint32_t field_offset, | |
165 uint32_t* decode_offset, | |
166 uint32_t* value); | |
167 | |
168 // Decodes an enum value, where the size (in bytes) of the encoding must be | |
169 // stated explicitly. It is assumed that under the covers enums are really | |
170 // just integers, and that we can static_cast them to and from uint32. | |
171 template <typename E> | |
172 bool SlowDecodeEnum(uint32_t field_size, | |
173 uint32_t field_offset, | |
174 uint32_t* decode_offset, | |
175 E* value) { | |
176 uint32_t tmp = static_cast<uint32_t>(*value); | |
177 const bool done = | |
178 SlowDecodeUnsignedInt(field_size, field_offset, decode_offset, &tmp); | |
179 *value = static_cast<E>(tmp); | |
180 DCHECK_EQ(tmp, static_cast<uint32_t>(*value)); | |
181 return done; | |
182 } | |
183 | |
184 // We assume the decode buffers will typically be modest in size (i.e. a few | |
185 // K). | |
186 // Let's make sure during testing that we don't go very high, with 32MB | |
187 // selected rather arbitrarily. | |
188 static constexpr size_t MaxDecodeBufferLength() { return 1 << 25; } | |
189 | |
190 protected: | |
191 #ifndef NDEBUG | |
192 // These are part of validating during tests that there is at most one | |
193 // DecodeBufferSubset instance at a time for any DecodeBuffer instance. | |
194 void set_subset_of_base(DecodeBuffer* base, | |
195 const DecodeBufferSubset* subset) { | |
196 DCHECK_EQ(this, subset); | |
197 base->set_subset(subset); | |
198 } | |
199 void clear_subset_of_base(DecodeBuffer* base, | |
200 const DecodeBufferSubset* subset) { | |
201 DCHECK_EQ(this, subset); | |
202 base->clear_subset(subset); | |
203 } | |
204 #endif | |
205 | |
206 private: | |
207 #ifndef NDEBUG | |
208 void set_subset(const DecodeBufferSubset* subset) { | |
209 DCHECK(subset != nullptr); | |
210 DCHECK_EQ(subset_, nullptr) << "There is already a subset"; | |
211 subset_ = subset; | |
212 } | |
213 void clear_subset(const DecodeBufferSubset* subset) { | |
214 DCHECK(subset != nullptr); | |
215 DCHECK_EQ(subset_, subset); | |
216 subset_ = nullptr; | |
217 } | |
218 #endif | |
219 | |
220 // Prevent heap allocation of DecodeBuffer. | |
221 static void* operator new(size_t s); | |
222 static void* operator new[](size_t s); | |
223 static void operator delete(void* p); | |
224 static void operator delete[](void* p); | |
225 | |
226 const char* const buffer_; | |
227 const char* cursor_; | |
228 const char* const beyond_; | |
229 const DecodeBufferSubset* subset_ = nullptr; // Used for DCHECKs. | |
230 | |
231 DISALLOW_COPY_AND_ASSIGN(DecodeBuffer); | |
232 }; | |
233 | |
234 // DecodeBufferSubset is used when decoding a known sized chunk of data, which | |
235 // starts at base->cursor(), and continues for subset_len, which may be | |
236 // entirely in |base|, or may extend beyond it (hence the MinLengthRemaining | |
237 // in the constructor). | |
238 // There are two benefits to using DecodeBufferSubset: it ensures that the | |
239 // cursor of |base| is advanced when the subset's destructor runs, and it | |
240 // ensures that the consumer of the subset can't go beyond the subset which | |
241 // it is intended to decode. | |
242 // There must be only a single DecodeBufferSubset at a time for a base | |
243 // DecodeBuffer, though they can be nested (i.e. a DecodeBufferSubset's | |
244 // base may itself be a DecodeBufferSubset). This avoids the AdvanceCursor | |
245 // being called erroneously. | |
246 class DecodeBufferSubset : public DecodeBuffer { | |
247 public: | |
248 DecodeBufferSubset(DecodeBuffer* base, size_t subset_len) | |
249 : DecodeBuffer(base->cursor(), base->MinLengthRemaining(subset_len)), | |
250 #ifndef NDEBUG | |
251 start_base_offset_(base->Offset()), | |
252 max_base_offset_(start_base_offset_ + FullSize()), | |
253 #endif | |
254 base_buffer_(base) { | |
255 #ifndef NDEBUG | |
256 DCHECK_LE(max_base_offset_, base->FullSize()); | |
257 set_subset_of_base(base_buffer_, this); | |
258 #endif | |
259 } | |
260 | |
261 ~DecodeBufferSubset() { | |
262 size_t offset = Offset(); | |
263 #ifndef NDEBUG | |
264 clear_subset_of_base(base_buffer_, this); | |
265 DCHECK_LE(Offset(), FullSize()); | |
266 DCHECK_EQ(start_base_offset_, base_buffer_->Offset()) | |
267 << "The base buffer was modified"; | |
268 DCHECK_LE(offset, FullSize()); | |
269 DCHECK_LE(start_base_offset_ + offset, base_buffer_->FullSize()); | |
270 #endif | |
271 base_buffer_->AdvanceCursor(offset); | |
272 #ifndef NDEBUG | |
273 DCHECK_GE(max_base_offset_, base_buffer_->Offset()); | |
274 #endif | |
275 } | |
276 | |
277 private: | |
278 #ifndef NDEBUG | |
279 const size_t start_base_offset_; // Used for DCHECKs. | |
280 const size_t max_base_offset_; // Used for DCHECKs. | |
281 #endif | |
282 DecodeBuffer* const base_buffer_; | |
283 | |
284 DISALLOW_COPY_AND_ASSIGN(DecodeBufferSubset); | |
285 }; | |
286 | |
287 } // namespace net | |
288 | |
289 #endif // NET_HTTP2_DECODER_DECODE_BUFFER_H_ | |
OLD | NEW |