xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/hpack/varint/hpack_varint_decoder.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 // HpackVarintDecoder decodes HPACK variable length unsigned integers. In HPACK,
6 // these integers are used to identify static or dynamic table index entries, to
7 // specify string lengths, and to update the size limit of the dynamic table.
8 // In QPACK, in addition to these uses, these integers also identify streams.
9 //
10 // The caller will need to validate that the decoded value is in an acceptable
11 // range.
12 //
13 // For details of the encoding, see:
14 //        http://httpwg.org/specs/rfc7541.html#integer.representation
15 //
16 // HpackVarintDecoder supports decoding any integer that can be represented on
17 // uint64_t, thereby exceeding the requirements for QPACK: "QPACK
18 // implementations MUST be able to decode integers up to 62 bits long."  See
19 // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5.1.1
20 //
21 // This decoder supports at most 10 extension bytes (bytes following the prefix,
22 // also called continuation bytes).  An encoder is allowed to zero pad the
23 // encoded integer on the left, thereby increasing the number of extension
24 // bytes.  If an encoder uses so much padding that the number of extension bytes
25 // exceeds the limit, then this decoder signals an error.
26 
27 #ifndef QUICHE_HTTP2_HPACK_VARINT_HPACK_VARINT_DECODER_H_
28 #define QUICHE_HTTP2_HPACK_VARINT_HPACK_VARINT_DECODER_H_
29 
30 #include <cstdint>
31 #include <limits>
32 #include <string>
33 
34 #include "quiche/http2/decoder/decode_buffer.h"
35 #include "quiche/http2/decoder/decode_status.h"
36 #include "quiche/common/platform/api/quiche_export.h"
37 #include "quiche/common/platform/api/quiche_logging.h"
38 
39 namespace http2 {
40 
41 // Sentinel value for |HpackVarintDecoder::offset_| to signify that decoding is
42 // completed.  Only used in debug builds.
43 #ifndef NDEBUG
44 const uint8_t kHpackVarintDecoderOffsetDone =
45     std::numeric_limits<uint8_t>::max();
46 #endif
47 
48 // Decodes an HPACK variable length unsigned integer, in a resumable fashion
49 // so it can handle running out of input in the DecodeBuffer. Call Start or
50 // StartExtended the first time (when decoding the byte that contains the
51 // prefix), then call Resume later if it is necessary to resume. When done,
52 // call value() to retrieve the decoded value.
53 //
54 // No constructor or destructor. Holds no resources, so destruction isn't
55 // needed. Start and StartExtended handles the initialization of member
56 // variables. This is necessary in order for HpackVarintDecoder to be part
57 // of a union.
58 class QUICHE_EXPORT HpackVarintDecoder {
59  public:
60   // |prefix_value| is the first byte of the encoded varint.
61   // |prefix_length| is number of bits in the first byte that are used for
62   // encoding the integer.  |db| is the rest of the buffer,  that is, not
63   // including the first byte.
64   DecodeStatus Start(uint8_t prefix_value, uint8_t prefix_length,
65                      DecodeBuffer* db);
66 
67   // The caller has already determined that the encoding requires multiple
68   // bytes, i.e. that the 3 to 8 low-order bits (the number determined by
69   // |prefix_length|) of the first byte are are all 1.  |db| is the rest of the
70   // buffer,  that is, not including the first byte.
71   DecodeStatus StartExtended(uint8_t prefix_length, DecodeBuffer* db);
72 
73   // Resume decoding a variable length integer after an earlier
74   // call to Start or StartExtended returned kDecodeInProgress.
75   DecodeStatus Resume(DecodeBuffer* db);
76 
77   uint64_t value() const;
78 
79   // This supports optimizations for the case of a varint with zero extension
80   // bytes, where the handling of the prefix is done by the caller.
81   void set_value(uint64_t v);
82 
83   // All the public methods below are for supporting assertions and tests.
84 
85   std::string DebugString() const;
86 
87   // For benchmarking, these methods ensure the decoder
88   // is NOT inlined into the caller.
89   DecodeStatus StartForTest(uint8_t prefix_value, uint8_t prefix_length,
90                             DecodeBuffer* db);
91   DecodeStatus StartExtendedForTest(uint8_t prefix_length, DecodeBuffer* db);
92   DecodeStatus ResumeForTest(DecodeBuffer* db);
93 
94  private:
95   // Protection in case Resume is called when it shouldn't be.
MarkDone()96   void MarkDone() {
97 #ifndef NDEBUG
98     offset_ = kHpackVarintDecoderOffsetDone;
99 #endif
100   }
CheckNotDone()101   void CheckNotDone() const {
102 #ifndef NDEBUG
103     QUICHE_DCHECK_NE(kHpackVarintDecoderOffsetDone, offset_);
104 #endif
105   }
CheckDone()106   void CheckDone() const {
107 #ifndef NDEBUG
108     QUICHE_DCHECK_EQ(kHpackVarintDecoderOffsetDone, offset_);
109 #endif
110   }
111 
112   // These fields are initialized just to keep ASAN happy about reading
113   // them from DebugString().
114 
115   // The encoded integer is being accumulated in |value_|.  When decoding is
116   // complete, |value_| holds the result.
117   uint64_t value_ = 0;
118 
119   // Each extension byte encodes in its lowest 7 bits a segment of the integer.
120   // |offset_| is the number of places this segment has to be shifted to the
121   // left for decoding.  It is zero for the first extension byte, and increases
122   // by 7 for each subsequent extension byte.
123   uint8_t offset_ = 0;
124 };
125 
126 }  // namespace http2
127 
128 #endif  // QUICHE_HTTP2_HPACK_VARINT_HPACK_VARINT_DECODER_H_
129