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 |