• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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