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 QUICHE_HTTP2_DECODER_DECODE_BUFFER_H_ 6 #define QUICHE_HTTP2_DECODER_DECODE_BUFFER_H_ 7 8 // DecodeBuffer provides primitives for decoding various integer types found in 9 // HTTP/2 frames. It wraps a byte array from which we can read and decode 10 // serialized HTTP/2 frames, or parts thereof. DecodeBuffer is intended only for 11 // stack allocation, where the caller is typically going to use the DecodeBuffer 12 // instance as part of decoding the entire buffer before returning to its own 13 // caller. 14 15 #include <stddef.h> 16 17 #include <algorithm> 18 #include <cstdint> 19 20 #include "absl/strings/string_view.h" 21 #include "quiche/common/platform/api/quiche_export.h" 22 #include "quiche/common/platform/api/quiche_logging.h" 23 24 namespace http2 { 25 class DecodeBufferSubset; 26 27 class QUICHE_EXPORT DecodeBuffer { 28 public: 29 // We assume the decode buffers will typically be modest in size (i.e. often a 30 // few KB, perhaps as high as 100KB). Let's make sure during testing that we 31 // don't go very high, with 32MB selected rather arbitrarily. This is exposed 32 // to support testing. 33 static constexpr size_t kMaxDecodeBufferLength = 1 << 25; 34 DecodeBuffer(const char * buffer,size_t len)35 DecodeBuffer(const char* buffer, size_t len) 36 : buffer_(buffer), cursor_(buffer), beyond_(buffer + len) { 37 QUICHE_DCHECK(buffer != nullptr); 38 QUICHE_DCHECK_LE(len, kMaxDecodeBufferLength); 39 } DecodeBuffer(absl::string_view s)40 explicit DecodeBuffer(absl::string_view s) 41 : DecodeBuffer(s.data(), s.size()) {} 42 // Constructor for character arrays, typically in tests. For example: 43 // const char input[] = { 0x11 }; 44 // DecodeBuffer b(input); 45 template <size_t N> DecodeBuffer(const char (& buf)[N])46 explicit DecodeBuffer(const char (&buf)[N]) : DecodeBuffer(buf, N) {} 47 48 DecodeBuffer(const DecodeBuffer&) = delete; 49 DecodeBuffer operator=(const DecodeBuffer&) = delete; 50 Empty()51 bool Empty() const { return cursor_ >= beyond_; } HasData()52 bool HasData() const { return cursor_ < beyond_; } Remaining()53 size_t Remaining() const { 54 QUICHE_DCHECK_LE(cursor_, beyond_); 55 return beyond_ - cursor_; 56 } Offset()57 size_t Offset() const { return cursor_ - buffer_; } FullSize()58 size_t FullSize() const { return beyond_ - buffer_; } 59 60 // Returns the minimum of the number of bytes remaining in this DecodeBuffer 61 // and |length|, in support of determining how much of some structure/payload 62 // is in this DecodeBuffer. MinLengthRemaining(size_t length)63 size_t MinLengthRemaining(size_t length) const { 64 return std::min(length, Remaining()); 65 } 66 67 // For string decoding, returns a pointer to the next byte/char to be decoded. cursor()68 const char* cursor() const { return cursor_; } 69 // Advances the cursor (pointer to the next byte/char to be decoded). AdvanceCursor(size_t amount)70 void AdvanceCursor(size_t amount) { 71 QUICHE_DCHECK_LE(amount, 72 Remaining()); // Need at least that much remaining. 73 QUICHE_DCHECK_EQ(subset_, nullptr) 74 << "Access via subset only when present."; 75 cursor_ += amount; 76 } 77 78 // Only call methods starting "Decode" when there is enough input remaining. DecodeChar()79 char DecodeChar() { 80 QUICHE_DCHECK_LE(1u, Remaining()); // Need at least one byte remaining. 81 QUICHE_DCHECK_EQ(subset_, nullptr) 82 << "Access via subset only when present."; 83 return *cursor_++; 84 } 85 86 uint8_t DecodeUInt8(); 87 uint16_t DecodeUInt16(); 88 uint32_t DecodeUInt24(); 89 90 // For 31-bit unsigned integers, where the 32nd bit is reserved for future 91 // use (i.e. the high-bit of the first byte of the encoding); examples: 92 // the Stream Id in a frame header or the Window Size Increment in a 93 // WINDOW_UPDATE frame. 94 uint32_t DecodeUInt31(); 95 96 uint32_t DecodeUInt32(); 97 98 protected: 99 #ifndef NDEBUG 100 // These are part of validating during tests that there is at most one 101 // DecodeBufferSubset instance at a time for any DecodeBuffer instance. 102 void set_subset_of_base(DecodeBuffer* base, const DecodeBufferSubset* subset); 103 void clear_subset_of_base(DecodeBuffer* base, 104 const DecodeBufferSubset* subset); 105 #endif 106 107 private: 108 #ifndef NDEBUG 109 void set_subset(const DecodeBufferSubset* subset); 110 void clear_subset(const DecodeBufferSubset* subset); 111 #endif 112 113 // Prevent heap allocation of DecodeBuffer. 114 static void* operator new(size_t s); 115 static void* operator new[](size_t s); 116 static void operator delete(void* p); 117 static void operator delete[](void* p); 118 119 const char* const buffer_; 120 const char* cursor_; 121 const char* const beyond_; 122 const DecodeBufferSubset* subset_ = nullptr; // Used for QUICHE_DCHECKs. 123 }; 124 125 // DecodeBufferSubset is used when decoding a known sized chunk of data, which 126 // starts at base->cursor(), and continues for subset_len, which may be 127 // entirely in |base|, or may extend beyond it (hence the MinLengthRemaining 128 // in the constructor). 129 // There are two benefits to using DecodeBufferSubset: it ensures that the 130 // cursor of |base| is advanced when the subset's destructor runs, and it 131 // ensures that the consumer of the subset can't go beyond the subset which 132 // it is intended to decode. 133 // There must be only a single DecodeBufferSubset at a time for a base 134 // DecodeBuffer, though they can be nested (i.e. a DecodeBufferSubset's 135 // base may itself be a DecodeBufferSubset). This avoids the AdvanceCursor 136 // being called erroneously. 137 class QUICHE_EXPORT DecodeBufferSubset : public DecodeBuffer { 138 public: DecodeBufferSubset(DecodeBuffer * base,size_t subset_len)139 DecodeBufferSubset(DecodeBuffer* base, size_t subset_len) 140 : DecodeBuffer(base->cursor(), base->MinLengthRemaining(subset_len)), 141 base_buffer_(base) { 142 #ifndef NDEBUG 143 DebugSetup(); 144 #endif 145 } 146 147 DecodeBufferSubset(const DecodeBufferSubset&) = delete; 148 DecodeBufferSubset operator=(const DecodeBufferSubset&) = delete; 149 ~DecodeBufferSubset()150 ~DecodeBufferSubset() { 151 size_t offset = Offset(); 152 #ifndef NDEBUG 153 DebugTearDown(); 154 #endif 155 base_buffer_->AdvanceCursor(offset); 156 } 157 158 private: 159 DecodeBuffer* const base_buffer_; 160 #ifndef NDEBUG 161 size_t start_base_offset_; // Used for QUICHE_DCHECKs. 162 size_t max_base_offset_; // Used for QUICHE_DCHECKs. 163 164 void DebugSetup(); 165 void DebugTearDown(); 166 #endif 167 }; 168 169 } // namespace http2 170 171 #endif // QUICHE_HTTP2_DECODER_DECODE_BUFFER_H_ 172