mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 09:46:09 +03:00
119 lines
4.7 KiB
C
119 lines
4.7 KiB
C
|
// 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.
|
||
|
|
||
|
// HpackVarintDecoder decodes HPACK variable length unsigned integers. These
|
||
|
// integers are used to identify static or dynamic table index entries, to
|
||
|
// specify string lengths, and to update the size limit of the dynamic table.
|
||
|
//
|
||
|
// The caller will need to validate that the decoded value is in an acceptable
|
||
|
// range.
|
||
|
//
|
||
|
// In order to support naive encoders (i.e. which always output 5 extension
|
||
|
// bytes for a uint32 that is >= prefix_mask), the decoder supports an an
|
||
|
// encoding with up to 5 extension bytes, and a maximum value of 268,435,582
|
||
|
// (4 "full" extension bytes plus the maximum for a prefix, 127). It could be
|
||
|
// modified to support a lower maximum value (by requiring that extensions bytes
|
||
|
// be "empty"), or a larger value if valuable for some reason I can't see.
|
||
|
//
|
||
|
// For details of the encoding, see:
|
||
|
// http://httpwg.org/specs/rfc7541.html#integer.representation
|
||
|
//
|
||
|
// TODO(jamessynge): Consider dropping support for encodings of more than 4
|
||
|
// bytes, including the prefix byte, as in practice we only see at most 3 bytes,
|
||
|
// and 4 bytes would cover any desire to support large (but not ridiculously
|
||
|
// large) header values.
|
||
|
|
||
|
#ifndef NET_HTTP2_HPACK_DECODER_HPACK_VARINT_DECODER_H_
|
||
|
#define NET_HTTP2_HPACK_DECODER_HPACK_VARINT_DECODER_H_
|
||
|
|
||
|
#include "base/logging.h"
|
||
|
#include "net/http2/decoder/decode_buffer.h"
|
||
|
#include "net/http2/decoder/decode_status.h"
|
||
|
#include "net/http2/platform/api/http2_export.h"
|
||
|
#include "net/http2/platform/api/http2_string.h"
|
||
|
|
||
|
namespace net {
|
||
|
// Decodes an HPACK variable length unsigned integer, in a resumable fashion
|
||
|
// so it can handle running out of input in the DecodeBuffer. Call Start or
|
||
|
// StartExtended the first time (when decoding the byte that contains the
|
||
|
// prefix), then call Resume later if it is necessary to resume. When done,
|
||
|
// call value() to retrieve the decoded value.
|
||
|
//
|
||
|
// No constructor or destructor. Holds no resources, so destruction isn't
|
||
|
// needed. Start and StartExtended handles the initialization of member
|
||
|
// variables. This is necessary in order for HpackVarintDecoder to be part
|
||
|
// of a union.
|
||
|
class HTTP2_EXPORT_PRIVATE HpackVarintDecoder {
|
||
|
public:
|
||
|
// |prefix_value| is the first byte of the encoded varint.
|
||
|
// |prefix_mask| is the mask of the valid bits, i.e. without the top 1 to 4
|
||
|
// high-bits set, as appropriate for the item being decoded; must be a
|
||
|
// contiguous sequence of set bits, starting with the low-order bits.
|
||
|
DecodeStatus Start(uint8_t prefix_value,
|
||
|
uint8_t prefix_mask,
|
||
|
DecodeBuffer* db);
|
||
|
|
||
|
// The caller has already determined that the encoding requires multiple
|
||
|
// bytes, i.e. that the 4 to 7 low-order bits (the number determined by the
|
||
|
// prefix length, a value not passed into this function) of the first byte are
|
||
|
// are all 1. The caller passes in |prefix_mask|, which is 2^prefix_length-1.
|
||
|
DecodeStatus StartExtended(uint8_t prefix_mask, DecodeBuffer* db);
|
||
|
|
||
|
// Resume decoding a variable length integer after an earlier
|
||
|
// call to Start or StartExtended returned kDecodeInProgress.
|
||
|
DecodeStatus Resume(DecodeBuffer* db);
|
||
|
|
||
|
uint32_t value() const;
|
||
|
|
||
|
// This supports optimizations for the case of a varint with zero extension
|
||
|
// bytes, where the handling of the prefix is done by the caller.
|
||
|
void set_value(uint32_t v);
|
||
|
|
||
|
// All the public methods below are for supporting assertions and tests.
|
||
|
|
||
|
Http2String DebugString() const;
|
||
|
|
||
|
// For benchmarking, these methods ensure the decoder
|
||
|
// is NOT inlined into the caller.
|
||
|
DecodeStatus StartForTest(uint8_t prefix_value,
|
||
|
uint8_t prefix_mask,
|
||
|
DecodeBuffer* db);
|
||
|
DecodeStatus StartExtendedForTest(uint8_t prefix_mask, DecodeBuffer* db);
|
||
|
DecodeStatus ResumeForTest(DecodeBuffer* db);
|
||
|
|
||
|
static constexpr uint32_t MaxExtensionBytes() { return 5; }
|
||
|
|
||
|
private:
|
||
|
// Protection in case Resume is called when it shouldn't be.
|
||
|
void MarkDone() {
|
||
|
#ifndef NDEBUG
|
||
|
// We support up to 5 extension bytes, so offset_ should never be > 28 when
|
||
|
// it makes sense to call Resume().
|
||
|
offset_ = MaxOffset() + 7;
|
||
|
#endif
|
||
|
}
|
||
|
void CheckNotDone() const {
|
||
|
#ifndef NDEBUG
|
||
|
DCHECK_LE(offset_, MaxOffset());
|
||
|
#endif
|
||
|
}
|
||
|
void CheckDone() const {
|
||
|
#ifndef NDEBUG
|
||
|
DCHECK_GT(offset_, MaxOffset());
|
||
|
#endif
|
||
|
}
|
||
|
static constexpr uint32_t MaxOffset() {
|
||
|
return 7 * (MaxExtensionBytes() - 1);
|
||
|
}
|
||
|
|
||
|
// These fields are initialized just to keep ASAN happy about reading
|
||
|
// them from DebugString().
|
||
|
uint32_t value_ = 0;
|
||
|
uint32_t offset_ = 0;
|
||
|
};
|
||
|
|
||
|
} // namespace net
|
||
|
|
||
|
#endif // NET_HTTP2_HPACK_DECODER_HPACK_VARINT_DECODER_H_
|