naiveproxy/net/quic/http/decoder/quic_http_decode_buffer.h
2018-01-28 13:32:06 -05:00

203 lines
7.3 KiB
C++

// Copyright 2017 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_QUIC_HTTP_DECODER_QUIC_HTTP_DECODE_BUFFER_H_
#define NET_QUIC_HTTP_DECODER_QUIC_HTTP_DECODE_BUFFER_H_
// QuicHttpDecodeBuffer 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. QuicHttpDecodeBuffer is
// intended only for stack allocation, where the caller is typically going to
// use the QuicHttpDecodeBuffer 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 "net/quic/platform/api/quic_export.h"
#include "net/quic/platform/api/quic_string_piece.h"
namespace net {
class QuicHttpDecodeBufferSubset;
class QUIC_EXPORT_PRIVATE QuicHttpDecodeBuffer {
public:
QuicHttpDecodeBuffer(const char* buffer, size_t len)
: buffer_(buffer), cursor_(buffer), beyond_(buffer + len) {
DCHECK(buffer != nullptr);
DCHECK_LE(len, MaxQuicHttpDecodeBufferLength());
}
explicit QuicHttpDecodeBuffer(QuicStringPiece s)
: QuicHttpDecodeBuffer(s.data(), s.size()) {}
// Constructor for character arrays, typically in tests. For example:
// const char input[] = { 0x11 };
// QuicHttpDecodeBuffer b(input);
template <size_t N>
explicit QuicHttpDecodeBuffer(const char (&buf)[N])
: QuicHttpDecodeBuffer(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
// QuicHttpDecodeBuffer and |length|, in support of determining how much of
// some structure/quic_http_payload is in this QuicHttpDecodeBuffer.
size_t MinLengthRemaining(size_t length) const {
return std::min(length, Remaining());
}
// For std::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 MaxQuicHttpDecodeBufferLength() { return 1 << 25; }
protected:
#ifndef NDEBUG
// These are part of validating during tests that there is at most one
// QuicHttpDecodeBufferSubset instance at a time for any DecodeBuffer
// instance.
void set_subset_of_base(QuicHttpDecodeBuffer* base,
const QuicHttpDecodeBufferSubset* subset);
void clear_subset_of_base(QuicHttpDecodeBuffer* base,
const QuicHttpDecodeBufferSubset* subset);
#endif
private:
#ifndef NDEBUG
void set_subset(const QuicHttpDecodeBufferSubset* subset);
void clear_subset(const QuicHttpDecodeBufferSubset* subset);
#endif
// Prevent heap allocation of QuicHttpDecodeBuffer.
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 QuicHttpDecodeBufferSubset* subset_ = nullptr; // Used for DCHECKs.
DISALLOW_COPY_AND_ASSIGN(QuicHttpDecodeBuffer);
};
// QuicHttpDecodeBufferSubset 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 QuicHttpDecodeBufferSubset: 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 QuicHttpDecodeBufferSubset at a time for a base
// QuicHttpDecodeBuffer, though they can be nested (i.e. a DecodeBufferSubset's
// base may itself be a QuicHttpDecodeBufferSubset). This avoids the
// AdvanceCursor being called erroneously.
class QUIC_EXPORT_PRIVATE QuicHttpDecodeBufferSubset
: public QuicHttpDecodeBuffer {
public:
QuicHttpDecodeBufferSubset(QuicHttpDecodeBuffer* base, size_t subset_len)
: QuicHttpDecodeBuffer(base->cursor(),
base->MinLengthRemaining(subset_len)),
base_buffer_(base) {
#ifndef NDEBUG
DebugSetup();
#endif
}
~QuicHttpDecodeBufferSubset() {
size_t offset = Offset();
#ifndef NDEBUG
DebugTearDown();
#endif
base_buffer_->AdvanceCursor(offset);
}
private:
QuicHttpDecodeBuffer* 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(QuicHttpDecodeBufferSubset);
};
} // namespace net
#endif // NET_QUIC_HTTP_DECODER_QUIC_HTTP_DECODE_BUFFER_H_