OLD | NEW |
| (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 #include "net/http2/hpack/decoder/hpack_entry_decoder.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/macros.h" | |
11 | |
12 namespace net { | |
13 namespace { | |
14 // Converts calls from HpackStringDecoder when decoding a header name into the | |
15 // appropriate HpackEntryDecoderListener::OnName* calls. | |
16 class NameDecoderListener { | |
17 public: | |
18 explicit NameDecoderListener(HpackEntryDecoderListener* listener) | |
19 : listener_(listener) {} | |
20 bool OnStringStart(bool huffman_encoded, size_t len) { | |
21 listener_->OnNameStart(huffman_encoded, len); | |
22 return true; | |
23 } | |
24 void OnStringData(const char* data, size_t len) { | |
25 listener_->OnNameData(data, len); | |
26 } | |
27 void OnStringEnd() { listener_->OnNameEnd(); } | |
28 | |
29 private: | |
30 HpackEntryDecoderListener* listener_; | |
31 }; | |
32 | |
33 // Converts calls from HpackStringDecoder when decoding a header value into | |
34 // the appropriate HpackEntryDecoderListener::OnValue* calls. | |
35 class ValueDecoderListener { | |
36 public: | |
37 explicit ValueDecoderListener(HpackEntryDecoderListener* listener) | |
38 : listener_(listener) {} | |
39 bool OnStringStart(bool huffman_encoded, size_t len) { | |
40 listener_->OnValueStart(huffman_encoded, len); | |
41 return true; | |
42 } | |
43 void OnStringData(const char* data, size_t len) { | |
44 listener_->OnValueData(data, len); | |
45 } | |
46 void OnStringEnd() { listener_->OnValueEnd(); } | |
47 | |
48 private: | |
49 HpackEntryDecoderListener* listener_; | |
50 }; | |
51 } // namespace | |
52 | |
53 // Only call Resume if the previous call (Start or Resume) returned | |
54 // kDecodeInProgress; Resume is also called from Start when it has succeeded | |
55 // in decoding the entry type and its varint. | |
56 DecodeStatus HpackEntryDecoder::Resume(DecodeBuffer* db, | |
57 HpackEntryDecoderListener* listener) { | |
58 DCHECK(db != nullptr); | |
59 DCHECK(listener != nullptr); | |
60 | |
61 DecodeStatus status; | |
62 | |
63 do { | |
64 switch (state_) { | |
65 case EntryDecoderState::kResumeDecodingType: | |
66 // entry_type_decoder_ returned kDecodeInProgress when last called. | |
67 DVLOG(1) << "kResumeDecodingType: db->Remaining=" << db->Remaining(); | |
68 status = entry_type_decoder_.Resume(db); | |
69 if (status != DecodeStatus::kDecodeDone) { | |
70 return status; | |
71 } | |
72 state_ = EntryDecoderState::kDecodedType; | |
73 // FALLTHROUGH_INTENDED | |
74 | |
75 case EntryDecoderState::kDecodedType: | |
76 // entry_type_decoder_ returned kDecodeDone, now need to decide how | |
77 // to proceed. | |
78 DVLOG(1) << "kDecodedType: db->Remaining=" << db->Remaining(); | |
79 if (DispatchOnType(listener)) { | |
80 // All done. | |
81 return DecodeStatus::kDecodeDone; | |
82 } | |
83 continue; | |
84 | |
85 case EntryDecoderState::kStartDecodingName: | |
86 DVLOG(1) << "kStartDecodingName: db->Remaining=" << db->Remaining(); | |
87 { | |
88 NameDecoderListener ncb(listener); | |
89 status = string_decoder_.Start(db, &ncb); | |
90 } | |
91 if (status != DecodeStatus::kDecodeDone) { | |
92 // On the assumption that the status is kDecodeInProgress, set | |
93 // state_ accordingly; unnecessary if status is kDecodeError, but | |
94 // that will only happen if the varint encoding the name's length | |
95 // is too long. | |
96 state_ = EntryDecoderState::kResumeDecodingName; | |
97 return status; | |
98 } | |
99 state_ = EntryDecoderState::kStartDecodingValue; | |
100 // FALLTHROUGH_INTENDED | |
101 | |
102 case EntryDecoderState::kStartDecodingValue: | |
103 DVLOG(1) << "kStartDecodingValue: db->Remaining=" << db->Remaining(); | |
104 { | |
105 ValueDecoderListener vcb(listener); | |
106 status = string_decoder_.Start(db, &vcb); | |
107 } | |
108 if (status == DecodeStatus::kDecodeDone) { | |
109 // Done with decoding the literal value, so we've reached the | |
110 // end of the header entry. | |
111 return status; | |
112 } | |
113 // On the assumption that the status is kDecodeInProgress, set | |
114 // state_ accordingly; unnecessary if status is kDecodeError, but | |
115 // that will only happen if the varint encoding the value's length | |
116 // is too long. | |
117 state_ = EntryDecoderState::kResumeDecodingValue; | |
118 return status; | |
119 | |
120 case EntryDecoderState::kResumeDecodingName: | |
121 // The literal name was split across decode buffers. | |
122 DVLOG(1) << "kResumeDecodingName: db->Remaining=" << db->Remaining(); | |
123 { | |
124 NameDecoderListener ncb(listener); | |
125 status = string_decoder_.Resume(db, &ncb); | |
126 } | |
127 if (status != DecodeStatus::kDecodeDone) { | |
128 // On the assumption that the status is kDecodeInProgress, set | |
129 // state_ accordingly; unnecessary if status is kDecodeError, but | |
130 // that will only happen if the varint encoding the name's length | |
131 // is too long. | |
132 state_ = EntryDecoderState::kResumeDecodingName; | |
133 return status; | |
134 } | |
135 state_ = EntryDecoderState::kStartDecodingValue; | |
136 break; | |
137 | |
138 case EntryDecoderState::kResumeDecodingValue: | |
139 // The literal value was split across decode buffers. | |
140 DVLOG(1) << "kResumeDecodingValue: db->Remaining=" << db->Remaining(); | |
141 { | |
142 ValueDecoderListener vcb(listener); | |
143 status = string_decoder_.Resume(db, &vcb); | |
144 } | |
145 if (status == DecodeStatus::kDecodeDone) { | |
146 // Done with decoding the value, therefore the entry as a whole. | |
147 return status; | |
148 } | |
149 // On the assumption that the status is kDecodeInProgress, set | |
150 // state_ accordingly; unnecessary if status is kDecodeError, but | |
151 // that will only happen if the varint encoding the value's length | |
152 // is too long. | |
153 state_ = EntryDecoderState::kResumeDecodingValue; | |
154 return status; | |
155 } | |
156 } while (true); | |
157 } | |
158 | |
159 bool HpackEntryDecoder::DispatchOnType(HpackEntryDecoderListener* listener) { | |
160 const HpackEntryType entry_type = entry_type_decoder_.entry_type(); | |
161 const uint32_t varint = entry_type_decoder_.varint(); | |
162 switch (entry_type) { | |
163 case HpackEntryType::kIndexedHeader: | |
164 // The entry consists solely of the entry type and varint. See: | |
165 // http://httpwg.org/specs/rfc7541.html#indexed.header.representation | |
166 listener->OnIndexedHeader(varint); | |
167 return true; | |
168 | |
169 case HpackEntryType::kIndexedLiteralHeader: | |
170 case HpackEntryType::kUnindexedLiteralHeader: | |
171 case HpackEntryType::kNeverIndexedLiteralHeader: | |
172 // The entry has a literal value, and if the varint is zero also has a | |
173 // literal name preceding the value. See: | |
174 // http://httpwg.org/specs/rfc7541.html#literal.header.representation | |
175 listener->OnStartLiteralHeader(entry_type, varint); | |
176 if (varint == 0) { | |
177 state_ = EntryDecoderState::kStartDecodingName; | |
178 } else { | |
179 state_ = EntryDecoderState::kStartDecodingValue; | |
180 } | |
181 return false; | |
182 | |
183 case HpackEntryType::kDynamicTableSizeUpdate: | |
184 // The entry consists solely of the entry type and varint. FWIW, I've | |
185 // never seen this type of entry in production (primarily browser | |
186 // traffic) so if you're designing an HPACK successor someday, consider | |
187 // dropping it or giving it a much longer prefix. See: | |
188 // http://httpwg.org/specs/rfc7541.html#encoding.context.update | |
189 listener->OnDynamicTableSizeUpdate(varint); | |
190 return true; | |
191 } | |
192 | |
193 NOTREACHED(); | |
194 return true; | |
195 } | |
196 | |
197 void HpackEntryDecoder::OutputDebugString(std::ostream& out) const { | |
198 out << "HpackEntryDecoder(state=" << state_ << ", " << entry_type_decoder_ | |
199 << ", " << string_decoder_ << ")"; | |
200 } | |
201 | |
202 std::string HpackEntryDecoder::DebugString() const { | |
203 std::stringstream s; | |
204 s << *this; | |
205 return s.str(); | |
206 } | |
207 | |
208 std::ostream& operator<<(std::ostream& out, const HpackEntryDecoder& v) { | |
209 v.OutputDebugString(out); | |
210 return out; | |
211 } | |
212 | |
213 std::ostream& operator<<(std::ostream& out, | |
214 HpackEntryDecoder::EntryDecoderState state) { | |
215 typedef HpackEntryDecoder::EntryDecoderState EntryDecoderState; | |
216 switch (state) { | |
217 case EntryDecoderState::kResumeDecodingType: | |
218 return out << "kResumeDecodingType"; | |
219 case EntryDecoderState::kDecodedType: | |
220 return out << "kDecodedType"; | |
221 case EntryDecoderState::kStartDecodingName: | |
222 return out << "kStartDecodingName"; | |
223 case EntryDecoderState::kResumeDecodingName: | |
224 return out << "kResumeDecodingName"; | |
225 case EntryDecoderState::kStartDecodingValue: | |
226 return out << "kStartDecodingValue"; | |
227 case EntryDecoderState::kResumeDecodingValue: | |
228 return out << "kResumeDecodingValue"; | |
229 } | |
230 return out << static_cast<int>(state); | |
231 } | |
232 | |
233 } // namespace net | |
OLD | NEW |