Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(523)

Side by Side Diff: net/http2/hpack/decoder/hpack_varint_decoder.h

Issue 2554683003: Revert of Add new HTTP/2 and HPACK decoder in net/http2/. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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. These
6 // 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 //
9 // The caller will need to validate that the decoded value is in an acceptable
10 // range.
11 //
12 // In order to support naive encoders (i.e. which always output 5 extension
13 // bytes for a uint32 that is >= prefix_mask), the decoder supports an an
14 // encoding with up to 5 extension bytes, and a maximum value of 268,435,582
15 // (4 "full" extension bytes plus the maximum for a prefix, 127). It could be
16 // modified to support a lower maximum value (by requiring that extensions bytes
17 // be "empty"), or a larger value if valuable for some reason I can't see.
18 //
19 // For details of the encoding, see:
20 // http://httpwg.org/specs/rfc7541.html#integer.representation
21 //
22 // TODO(jamessynge): Consider dropping support for encodings of more than 4
23 // bytes, including the prefix byte, as in practice we only see at most 3 bytes,
24 // and 4 bytes would cover any desire to support large (but not ridiculously
25 // large) header values.
26
27 #ifndef NET_HTTP2_HPACK_DECODER_HPACK_VARINT_DECODER_H_
28 #define NET_HTTP2_HPACK_DECODER_HPACK_VARINT_DECODER_H_
29
30 #include <string>
31
32 #include "base/logging.h"
33 #include "net/base/net_export.h"
34 #include "net/http2/decoder/decode_buffer.h"
35 #include "net/http2/decoder/decode_status.h"
36
37 namespace net {
38 // Decodes an HPACK variable length unsigned integer, in a resumable fashion
39 // so it can handle running out of input in the DecodeBuffer. Call Start or
40 // StartExtended the first time (when decoding the byte that contains the
41 // prefix), then call Resume later if it is necessary to resume. When done,
42 // call value() to retrieve the decoded value.
43 //
44 // No constructor or destructor. Holds no resources, so destruction isn't
45 // needed. Start and StartExtended handles the initialization of member
46 // variables. This is necessary in order for HpackVarintDecoder to be part
47 // of a union.
48 class NET_EXPORT_PRIVATE HpackVarintDecoder {
49 public:
50 // |prefix_value| is the first byte of the encoded varint.
51 // |prefix_mask| is the mask of the valid bits, i.e. without the top 1 to 4
52 // high-bits set, as appropriate for the item being decoded; must be a
53 // contiguous sequence of set bits, starting with the low-order bits.
54 DecodeStatus Start(uint8_t prefix_value,
55 uint8_t prefix_mask,
56 DecodeBuffer* db) {
57 DCHECK_LE(15, prefix_mask) << std::hex << prefix_mask;
58 DCHECK_LE(prefix_mask, 127) << std::hex << prefix_mask;
59 // Confirm that |prefix_mask| is a contiguous sequence of bits.
60 DCHECK_EQ(0, (prefix_mask + 1) & prefix_mask) << std::hex << prefix_mask;
61
62 // Ignore the bits that aren't a part of the prefix of the varint.
63 value_ = prefix_value & prefix_mask;
64
65 if (value_ < prefix_mask) {
66 MarkDone();
67 return DecodeStatus::kDecodeDone;
68 }
69
70 offset_ = 0;
71 return Resume(db);
72 }
73
74 // The caller has already determined that the encoding requires multiple
75 // bytes, i.e. that the 4 to 7 low-order bits (the number determined by the
76 // prefix length, a value not passed into this function) of the first byte are
77 // are all 1. The caller passes in |prefix_mask|, which is 2^prefix_length-1.
78 DecodeStatus StartExtended(uint8_t prefix_mask, DecodeBuffer* db) {
79 DCHECK_LE(15, prefix_mask) << std::hex << prefix_mask;
80 DCHECK_LE(prefix_mask, 127) << std::hex << prefix_mask;
81 // Confirm that |prefix_mask| is a contiguous sequence of bits.
82 DCHECK_EQ(0, prefix_mask & (prefix_mask + 1)) << std::hex << prefix_mask;
83
84 value_ = prefix_mask;
85 offset_ = 0;
86 return Resume(db);
87 }
88
89 // Resume decoding a variable length integer after an earlier
90 // call to Start or StartExtended returned kDecodeInProgress.
91 DecodeStatus Resume(DecodeBuffer* db) {
92 CheckNotDone();
93 do {
94 if (db->Empty()) {
95 return DecodeStatus::kDecodeInProgress;
96 }
97 uint8_t byte = db->DecodeUInt8();
98 value_ += (byte & 0x7f) << offset_;
99 if ((byte & 0x80) == 0) {
100 if (offset_ < MaxOffset() || byte == 0) {
101 MarkDone();
102 return DecodeStatus::kDecodeDone;
103 }
104 break;
105 }
106 offset_ += 7;
107 } while (offset_ <= MaxOffset());
108 DLOG(WARNING) << "Variable length int encoding is too large or too long. "
109 << DebugString();
110 MarkDone();
111 return DecodeStatus::kDecodeError;
112 }
113
114 uint32_t value() const {
115 CheckDone();
116 return value_;
117 }
118
119 // This supports optimizations for the case of a varint with zero extension
120 // bytes, where the handling of the prefix is done by the caller.
121 void set_value(uint32_t v) {
122 MarkDone();
123 value_ = v;
124 }
125
126 // All the public methods below are for supporting assertions and tests.
127
128 std::string DebugString() const;
129
130 // For benchmarking, these methods ensure the decoder
131 // is NOT inlined into the caller.
132 DecodeStatus StartForTest(uint8_t prefix_value,
133 uint8_t prefix_mask,
134 DecodeBuffer* db);
135 DecodeStatus StartExtendedForTest(uint8_t prefix_mask, DecodeBuffer* db);
136 DecodeStatus ResumeForTest(DecodeBuffer* db);
137
138 static constexpr uint32_t MaxExtensionBytes() { return 5; }
139
140 // Returns the highest value with the specified number of extension bytes and
141 // the specified prefix length (bits).
142 static uint64_t constexpr HiValueOfExtensionBytes(uint32_t extension_bytes,
143 uint32_t prefix_length) {
144 return (1 << prefix_length) - 2 +
145 (extension_bytes == 0 ? 0 : (1LLU << (extension_bytes * 7)));
146 }
147
148 private:
149 // Protection in case Resume is called when it shouldn't be.
150 void MarkDone() {
151 #ifndef NDEBUG
152 // We support up to 5 extension bytes, so offset_ should never be > 28 when
153 // it makes sense to call Resume().
154 offset_ = MaxOffset() + 7;
155 #endif
156 }
157 void CheckNotDone() const {
158 #ifndef NDEBUG
159 DCHECK_LE(offset_, MaxOffset());
160 #endif
161 }
162 void CheckDone() const {
163 #ifndef NDEBUG
164 DCHECK_GT(offset_, MaxOffset());
165 #endif
166 }
167 static constexpr uint32_t MaxOffset() {
168 return 7 * (MaxExtensionBytes() - 1);
169 }
170
171 // These fields are initialized just to keep ASAN happy about reading
172 // them from DebugString().
173 uint32_t value_ = 0;
174 uint32_t offset_ = 0;
175 };
176
177 std::ostream& operator<<(std::ostream& out, const HpackVarintDecoder& v);
178
179 } // namespace net
180
181 #endif // NET_HTTP2_HPACK_DECODER_HPACK_VARINT_DECODER_H_
OLDNEW
« no previous file with comments | « net/http2/hpack/decoder/hpack_string_decoder_test.cc ('k') | net/http2/hpack/decoder/hpack_varint_decoder.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698