• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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