summaryrefslogtreecommitdiff
path: root/chromium/net/http2/decoder/decode_buffer.h
blob: 06aa128ad3a721e7cc33fb0e68211eedf9e346e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_HTTP2_DECODER_DECODE_BUFFER_H_
#define NET_HTTP2_DECODER_DECODE_BUFFER_H_

// DecodeBuffer provides primitives for decoding various integer types found in
// HTTP/2 frames. It wraps a byte array from which we can read and decode
// serialized HTTP/2 frames, or parts thereof. DecodeBuffer is intended only for
// stack allocation, where the caller is typically going to use the DecodeBuffer
// instance as part of decoding the entire buffer before returning to its own
// caller.

#include <stddef.h>
#include <stdint.h>

#include <algorithm>

#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"

namespace net {
class DecodeBufferSubset;

class NET_EXPORT_PRIVATE DecodeBuffer {
 public:
  DecodeBuffer(const char* buffer, size_t len)
      : buffer_(buffer), cursor_(buffer), beyond_(buffer + len) {
    DCHECK(buffer != nullptr);
    DCHECK_LE(len, MaxDecodeBufferLength());
  }
  explicit DecodeBuffer(base::StringPiece s)
      : DecodeBuffer(s.data(), s.size()) {}
  // Constructor for character arrays, typically in tests. For example:
  //    const char input[] = { 0x11 };
  //    DecodeBuffer b(input);
  template <size_t N>
  explicit DecodeBuffer(const char (&buf)[N]) : DecodeBuffer(buf, N) {}

  bool Empty() const { return cursor_ >= beyond_; }
  bool HasData() const { return cursor_ < beyond_; }
  size_t Remaining() const {
    DCHECK_LE(cursor_, beyond_);
    return beyond_ - cursor_;
  }
  size_t Offset() const { return cursor_ - buffer_; }
  size_t FullSize() const { return beyond_ - buffer_; }

  // Returns the minimum of the number of bytes remaining in this DecodeBuffer
  // and |length|, in support of determining how much of some structure/payload
  // is in this DecodeBuffer.
  size_t MinLengthRemaining(size_t length) const {
    return std::min(length, Remaining());
  }

  // For string decoding, returns a pointer to the next byte/char to be decoded.
  const char* cursor() const { return cursor_; }
  // Advances the cursor (pointer to the next byte/char to be decoded).
  void AdvanceCursor(size_t amount) {
    DCHECK_LE(amount, Remaining());  // Need at least that much remaining.
    DCHECK_EQ(subset_, nullptr) << "Access via subset only when present.";
    cursor_ += amount;
  }

  // Only call methods starting "Decode" when there is enough input remaining.
  char DecodeChar() {
    DCHECK_LE(1u, Remaining());  // Need at least one byte remaining.
    DCHECK_EQ(subset_, nullptr) << "Access via subset only when present.";
    return *cursor_++;
  }

  uint8_t DecodeUInt8() { return static_cast<uint8_t>(DecodeChar()); }

  uint16_t DecodeUInt16() {
    DCHECK_LE(2u, Remaining());
    const uint8_t b1 = DecodeUInt8();
    const uint8_t b2 = DecodeUInt8();
    // Note that chars are automatically promoted to ints during arithmetic,
    // so the b1 << 8 doesn't end up as zero before being or-ed with b2.
    // And the left-shift operator has higher precedence than the or operator.
    return b1 << 8 | b2;
  }

  uint32_t DecodeUInt24() {
    DCHECK_LE(3u, Remaining());
    const uint8_t b1 = DecodeUInt8();
    const uint8_t b2 = DecodeUInt8();
    const uint8_t b3 = DecodeUInt8();
    return b1 << 16 | b2 << 8 | b3;
  }

  // For 31-bit unsigned integers, where the 32nd bit is reserved for future
  // use (i.e. the high-bit of the first byte of the encoding); examples:
  // the Stream Id in a frame header or the Window Size Increment in a
  // WINDOW_UPDATE frame.
  uint32_t DecodeUInt31() {
    DCHECK_LE(4u, Remaining());
    const uint8_t b1 = DecodeUInt8() & 0x7f;  // Mask out the high order bit.
    const uint8_t b2 = DecodeUInt8();
    const uint8_t b3 = DecodeUInt8();
    const uint8_t b4 = DecodeUInt8();
    return b1 << 24 | b2 << 16 | b3 << 8 | b4;
  }

  uint32_t DecodeUInt32() {
    DCHECK_LE(4u, Remaining());
    const uint8_t b1 = DecodeUInt8();
    const uint8_t b2 = DecodeUInt8();
    const uint8_t b3 = DecodeUInt8();
    const uint8_t b4 = DecodeUInt8();
    return b1 << 24 | b2 << 16 | b3 << 8 | b4;
  }

  // We assume the decode buffers will typically be modest in size (i.e. often a
  // few KB, perhaps as high as 100KB). Let's make sure during testing that we
  // don't go very high, with 32MB selected rather arbitrarily.
  static constexpr size_t MaxDecodeBufferLength() { return 1 << 25; }

 protected:
#ifndef NDEBUG
  // These are part of validating during tests that there is at most one
  // DecodeBufferSubset instance at a time for any DecodeBuffer instance.
  void set_subset_of_base(DecodeBuffer* base, const DecodeBufferSubset* subset);
  void clear_subset_of_base(DecodeBuffer* base,
                            const DecodeBufferSubset* subset);
#endif

 private:
#ifndef NDEBUG
  void set_subset(const DecodeBufferSubset* subset);
  void clear_subset(const DecodeBufferSubset* subset);
#endif

  // Prevent heap allocation of DecodeBuffer.
  static void* operator new(size_t s);
  static void* operator new[](size_t s);
  static void operator delete(void* p);
  static void operator delete[](void* p);

  const char* const buffer_;
  const char* cursor_;
  const char* const beyond_;
  const DecodeBufferSubset* subset_ = nullptr;  // Used for DCHECKs.

  DISALLOW_COPY_AND_ASSIGN(DecodeBuffer);
};

// DecodeBufferSubset is used when decoding a known sized chunk of data, which
// starts at base->cursor(), and continues for subset_len, which may be
// entirely in |base|, or may extend beyond it (hence the MinLengthRemaining
// in the constructor).
// There are two benefits to using DecodeBufferSubset: it ensures that the
// cursor of |base| is advanced when the subset's destructor runs, and it
// ensures that the consumer of the subset can't go beyond the subset which
// it is intended to decode.
// There must be only a single DecodeBufferSubset at a time for a base
// DecodeBuffer, though they can be nested (i.e. a DecodeBufferSubset's
// base may itself be a DecodeBufferSubset). This avoids the AdvanceCursor
// being called erroneously.
class NET_EXPORT_PRIVATE DecodeBufferSubset : public DecodeBuffer {
 public:
  DecodeBufferSubset(DecodeBuffer* base, size_t subset_len)
      : DecodeBuffer(base->cursor(), base->MinLengthRemaining(subset_len)),
        base_buffer_(base) {
#ifndef NDEBUG
    DebugSetup();
#endif
  }

  ~DecodeBufferSubset() {
    size_t offset = Offset();
#ifndef NDEBUG
    DebugTearDown();
#endif
    base_buffer_->AdvanceCursor(offset);
  }

 private:
  DecodeBuffer* const base_buffer_;
#ifndef NDEBUG
  size_t start_base_offset_;  // Used for DCHECKs.
  size_t max_base_offset_;    // Used for DCHECKs.

  void DebugSetup();
  void DebugTearDown();
#endif

  DISALLOW_COPY_AND_ASSIGN(DecodeBufferSubset);
};

}  // namespace net

#endif  // NET_HTTP2_DECODER_DECODE_BUFFER_H_