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