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 #include "quiche/http2/hpack/decoder/hpack_entry_decoder.h"
6
7 #include <stddef.h>
8
9 #include <cstdint>
10
11 #include "absl/base/macros.h"
12 #include "quiche/common/platform/api/quiche_bug_tracker.h"
13 #include "quiche/common/platform/api/quiche_flag_utils.h"
14 #include "quiche/common/platform/api/quiche_logging.h"
15
16 namespace http2 {
17 namespace {
18 // Converts calls from HpackStringDecoder when decoding a header name into the
19 // appropriate HpackEntryDecoderListener::OnName* calls.
20 class NameDecoderListener {
21 public:
NameDecoderListener(HpackEntryDecoderListener * listener)22 explicit NameDecoderListener(HpackEntryDecoderListener* listener)
23 : listener_(listener) {}
OnStringStart(bool huffman_encoded,size_t len)24 bool OnStringStart(bool huffman_encoded, size_t len) {
25 listener_->OnNameStart(huffman_encoded, len);
26 return true;
27 }
OnStringData(const char * data,size_t len)28 void OnStringData(const char* data, size_t len) {
29 listener_->OnNameData(data, len);
30 }
OnStringEnd()31 void OnStringEnd() { listener_->OnNameEnd(); }
32
33 private:
34 HpackEntryDecoderListener* listener_;
35 };
36
37 // Converts calls from HpackStringDecoder when decoding a header value into
38 // the appropriate HpackEntryDecoderListener::OnValue* calls.
39 class ValueDecoderListener {
40 public:
ValueDecoderListener(HpackEntryDecoderListener * listener)41 explicit ValueDecoderListener(HpackEntryDecoderListener* listener)
42 : listener_(listener) {}
OnStringStart(bool huffman_encoded,size_t len)43 bool OnStringStart(bool huffman_encoded, size_t len) {
44 listener_->OnValueStart(huffman_encoded, len);
45 return true;
46 }
OnStringData(const char * data,size_t len)47 void OnStringData(const char* data, size_t len) {
48 listener_->OnValueData(data, len);
49 }
OnStringEnd()50 void OnStringEnd() { listener_->OnValueEnd(); }
51
52 private:
53 HpackEntryDecoderListener* listener_;
54 };
55 } // namespace
56
Start(DecodeBuffer * db,HpackEntryDecoderListener * listener)57 DecodeStatus HpackEntryDecoder::Start(DecodeBuffer* db,
58 HpackEntryDecoderListener* listener) {
59 QUICHE_DCHECK(db != nullptr);
60 QUICHE_DCHECK(listener != nullptr);
61 QUICHE_DCHECK(db->HasData());
62 DecodeStatus status = entry_type_decoder_.Start(db);
63 switch (status) {
64 case DecodeStatus::kDecodeDone:
65 // The type of the entry and its varint fit into the current decode
66 // buffer.
67 if (entry_type_decoder_.entry_type() == HpackEntryType::kIndexedHeader) {
68 // The entry consists solely of the entry type and varint.
69 // This is by far the most common case in practice.
70 listener->OnIndexedHeader(entry_type_decoder_.varint());
71 return DecodeStatus::kDecodeDone;
72 }
73 state_ = EntryDecoderState::kDecodedType;
74 return Resume(db, listener);
75 case DecodeStatus::kDecodeInProgress:
76 // Hit the end of the decode buffer before fully decoding
77 // the entry type and varint.
78 QUICHE_DCHECK_EQ(0u, db->Remaining());
79 state_ = EntryDecoderState::kResumeDecodingType;
80 return status;
81 case DecodeStatus::kDecodeError:
82 QUICHE_CODE_COUNT_N(decompress_failure_3, 11, 23);
83 error_ = HpackDecodingError::kIndexVarintError;
84 // The varint must have been invalid (too long).
85 return status;
86 }
87
88 QUICHE_BUG(http2_bug_63_1) << "Unreachable";
89 return DecodeStatus::kDecodeError;
90 }
91
Resume(DecodeBuffer * db,HpackEntryDecoderListener * listener)92 DecodeStatus HpackEntryDecoder::Resume(DecodeBuffer* db,
93 HpackEntryDecoderListener* listener) {
94 QUICHE_DCHECK(db != nullptr);
95 QUICHE_DCHECK(listener != nullptr);
96
97 DecodeStatus status;
98
99 do {
100 switch (state_) {
101 case EntryDecoderState::kResumeDecodingType:
102 // entry_type_decoder_ returned kDecodeInProgress when last called.
103 QUICHE_DVLOG(1) << "kResumeDecodingType: db->Remaining="
104 << db->Remaining();
105 status = entry_type_decoder_.Resume(db);
106 if (status == DecodeStatus::kDecodeError) {
107 QUICHE_CODE_COUNT_N(decompress_failure_3, 12, 23);
108 error_ = HpackDecodingError::kIndexVarintError;
109 }
110 if (status != DecodeStatus::kDecodeDone) {
111 return status;
112 }
113 state_ = EntryDecoderState::kDecodedType;
114 ABSL_FALLTHROUGH_INTENDED;
115
116 case EntryDecoderState::kDecodedType:
117 // entry_type_decoder_ returned kDecodeDone, now need to decide how
118 // to proceed.
119 QUICHE_DVLOG(1) << "kDecodedType: db->Remaining=" << db->Remaining();
120 if (DispatchOnType(listener)) {
121 // All done.
122 return DecodeStatus::kDecodeDone;
123 }
124 continue;
125
126 case EntryDecoderState::kStartDecodingName:
127 QUICHE_DVLOG(1) << "kStartDecodingName: db->Remaining="
128 << db->Remaining();
129 {
130 NameDecoderListener ncb(listener);
131 status = string_decoder_.Start(db, &ncb);
132 }
133 if (status != DecodeStatus::kDecodeDone) {
134 // On the assumption that the status is kDecodeInProgress, set
135 // state_ accordingly; unnecessary if status is kDecodeError, but
136 // that will only happen if the varint encoding the name's length
137 // is too long.
138 state_ = EntryDecoderState::kResumeDecodingName;
139 if (status == DecodeStatus::kDecodeError) {
140 QUICHE_CODE_COUNT_N(decompress_failure_3, 13, 23);
141 error_ = HpackDecodingError::kNameLengthVarintError;
142 }
143 return status;
144 }
145 state_ = EntryDecoderState::kStartDecodingValue;
146 ABSL_FALLTHROUGH_INTENDED;
147
148 case EntryDecoderState::kStartDecodingValue:
149 QUICHE_DVLOG(1) << "kStartDecodingValue: db->Remaining="
150 << db->Remaining();
151 {
152 ValueDecoderListener vcb(listener);
153 status = string_decoder_.Start(db, &vcb);
154 }
155 if (status == DecodeStatus::kDecodeError) {
156 QUICHE_CODE_COUNT_N(decompress_failure_3, 14, 23);
157 error_ = HpackDecodingError::kValueLengthVarintError;
158 }
159 if (status == DecodeStatus::kDecodeDone) {
160 // Done with decoding the literal value, so we've reached the
161 // end of the header entry.
162 return status;
163 }
164 // On the assumption that the status is kDecodeInProgress, set
165 // state_ accordingly; unnecessary if status is kDecodeError, but
166 // that will only happen if the varint encoding the value's length
167 // is too long.
168 state_ = EntryDecoderState::kResumeDecodingValue;
169 return status;
170
171 case EntryDecoderState::kResumeDecodingName:
172 // The literal name was split across decode buffers.
173 QUICHE_DVLOG(1) << "kResumeDecodingName: db->Remaining="
174 << db->Remaining();
175 {
176 NameDecoderListener ncb(listener);
177 status = string_decoder_.Resume(db, &ncb);
178 }
179 if (status != DecodeStatus::kDecodeDone) {
180 // On the assumption that the status is kDecodeInProgress, set
181 // state_ accordingly; unnecessary if status is kDecodeError, but
182 // that will only happen if the varint encoding the name's length
183 // is too long.
184 state_ = EntryDecoderState::kResumeDecodingName;
185 if (status == DecodeStatus::kDecodeError) {
186 QUICHE_CODE_COUNT_N(decompress_failure_3, 15, 23);
187 error_ = HpackDecodingError::kNameLengthVarintError;
188 }
189 return status;
190 }
191 state_ = EntryDecoderState::kStartDecodingValue;
192 break;
193
194 case EntryDecoderState::kResumeDecodingValue:
195 // The literal value was split across decode buffers.
196 QUICHE_DVLOG(1) << "kResumeDecodingValue: db->Remaining="
197 << db->Remaining();
198 {
199 ValueDecoderListener vcb(listener);
200 status = string_decoder_.Resume(db, &vcb);
201 }
202 if (status == DecodeStatus::kDecodeError) {
203 QUICHE_CODE_COUNT_N(decompress_failure_3, 16, 23);
204 error_ = HpackDecodingError::kValueLengthVarintError;
205 }
206 if (status == DecodeStatus::kDecodeDone) {
207 // Done with decoding the value, therefore the entry as a whole.
208 return status;
209 }
210 // On the assumption that the status is kDecodeInProgress, set
211 // state_ accordingly; unnecessary if status is kDecodeError, but
212 // that will only happen if the varint encoding the value's length
213 // is too long.
214 state_ = EntryDecoderState::kResumeDecodingValue;
215 return status;
216 }
217 } while (true);
218 }
219
DispatchOnType(HpackEntryDecoderListener * listener)220 bool HpackEntryDecoder::DispatchOnType(HpackEntryDecoderListener* listener) {
221 const HpackEntryType entry_type = entry_type_decoder_.entry_type();
222 const uint32_t varint = static_cast<uint32_t>(entry_type_decoder_.varint());
223 switch (entry_type) {
224 case HpackEntryType::kIndexedHeader:
225 // The entry consists solely of the entry type and varint. See:
226 // http://httpwg.org/specs/rfc7541.html#indexed.header.representation
227 listener->OnIndexedHeader(varint);
228 return true;
229
230 case HpackEntryType::kIndexedLiteralHeader:
231 case HpackEntryType::kUnindexedLiteralHeader:
232 case HpackEntryType::kNeverIndexedLiteralHeader:
233 // The entry has a literal value, and if the varint is zero also has a
234 // literal name preceding the value. See:
235 // http://httpwg.org/specs/rfc7541.html#literal.header.representation
236 listener->OnStartLiteralHeader(entry_type, varint);
237 if (varint == 0) {
238 state_ = EntryDecoderState::kStartDecodingName;
239 } else {
240 state_ = EntryDecoderState::kStartDecodingValue;
241 }
242 return false;
243
244 case HpackEntryType::kDynamicTableSizeUpdate:
245 // The entry consists solely of the entry type and varint. FWIW, I've
246 // never seen this type of entry in production (primarily browser
247 // traffic) so if you're designing an HPACK successor someday, consider
248 // dropping it or giving it a much longer prefix. See:
249 // http://httpwg.org/specs/rfc7541.html#encoding.context.update
250 listener->OnDynamicTableSizeUpdate(varint);
251 return true;
252 }
253
254 QUICHE_BUG(http2_bug_63_2) << "Unreachable, entry_type=" << entry_type;
255 return true;
256 }
257
OutputDebugString(std::ostream & out) const258 void HpackEntryDecoder::OutputDebugString(std::ostream& out) const {
259 out << "HpackEntryDecoder(state=" << state_ << ", " << entry_type_decoder_
260 << ", " << string_decoder_ << ")";
261 }
262
DebugString() const263 std::string HpackEntryDecoder::DebugString() const {
264 std::stringstream s;
265 s << *this;
266 return s.str();
267 }
268
operator <<(std::ostream & out,const HpackEntryDecoder & v)269 std::ostream& operator<<(std::ostream& out, const HpackEntryDecoder& v) {
270 v.OutputDebugString(out);
271 return out;
272 }
273
operator <<(std::ostream & out,HpackEntryDecoder::EntryDecoderState state)274 std::ostream& operator<<(std::ostream& out,
275 HpackEntryDecoder::EntryDecoderState state) {
276 typedef HpackEntryDecoder::EntryDecoderState EntryDecoderState;
277 switch (state) {
278 case EntryDecoderState::kResumeDecodingType:
279 return out << "kResumeDecodingType";
280 case EntryDecoderState::kDecodedType:
281 return out << "kDecodedType";
282 case EntryDecoderState::kStartDecodingName:
283 return out << "kStartDecodingName";
284 case EntryDecoderState::kResumeDecodingName:
285 return out << "kResumeDecodingName";
286 case EntryDecoderState::kStartDecodingValue:
287 return out << "kStartDecodingValue";
288 case EntryDecoderState::kResumeDecodingValue:
289 return out << "kResumeDecodingValue";
290 }
291 return out << static_cast<int>(state);
292 }
293
294 } // namespace http2
295