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