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