Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1209)

Side by Side Diff: net/http2/decoder/decode_buffer.h

Issue 2554683003: Revert of Add new HTTP/2 and HPACK decoder in net/http2/. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | net/http2/decoder/decode_buffer.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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_
OLDNEW
« no previous file with comments | « no previous file | net/http2/decoder/decode_buffer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698