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

Side by Side Diff: net/spdy/hpack/hpack_decoder2.cc

Issue 2750853008: Remove HpackDecoder2. (Closed)
Patch Set: Created 3 years, 9 months 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
« no previous file with comments | « net/spdy/hpack/hpack_decoder2.h ('k') | net/spdy/hpack/hpack_decoder2_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #include "net/spdy/hpack/hpack_decoder2.h"
6
7 #include <list>
8 #include <utility>
9
10 #include "base/logging.h"
11 #include "base/strings/string_piece.h"
12 #include "net/http2/decoder/decode_buffer.h"
13 #include "net/http2/decoder/decode_status.h"
14 #include "net/spdy/hpack/hpack_entry.h"
15 #include "net/spdy/platform/api/spdy_estimate_memory_usage.h"
16
17 using base::StringPiece;
18
19 namespace net {
20
21 HpackDecoder2::HpackDecoder2() : hpack_block_decoder_(this) {
22 Reset();
23 }
24
25 HpackDecoder2::~HpackDecoder2() {}
26
27 void HpackDecoder2::Reset() {
28 DVLOG(2) << "HpackDecoder2::Reset";
29 handler_ = nullptr;
30
31 hpack_block_decoder_.Reset();
32 hpack_block_decoder_.set_listener(this);
33
34 total_hpack_bytes_ = 0;
35 total_header_bytes_ = 0;
36 size_update_count_ = 0;
37 header_seen_ = false;
38 in_progress_ = false;
39 error_detected_ = false;
40 header_block_started_ = false;
41
42 name_.Reset();
43 value_.Reset();
44 }
45
46 void HpackDecoder2::SetErrorDetected() {
47 if (!error_detected_) {
48 DVLOG(2) << "HpackDecoder2::SetErrorDetected";
49 hpack_block_decoder_.set_listener(&no_op_listener_);
50 error_detected_ = true;
51 }
52 }
53
54 void HpackDecoder2::ApplyHeaderTableSizeSetting(size_t size_setting) {
55 DVLOG(2) << "HpackDecoder2::ApplyHeaderTableSizeSetting";
56 header_table_.SetSettingsHeaderTableSize(size_setting);
57 }
58
59 // If a SpdyHeadersHandlerInterface is provided, the decoder will emit
60 // headers to it rather than accumulating them in a SpdyHeaderBlock.
61 void HpackDecoder2::HandleControlFrameHeadersStart(
62 SpdyHeadersHandlerInterface* handler) {
63 DVLOG(2) << "HpackDecoder2::HandleControlFrameHeadersStart";
64 DCHECK(!header_block_started_);
65 handler_ = handler;
66 }
67
68 // Called as HPACK block fragments arrive. Returns false
69 // if an error occurred while decoding the block.
70 bool HpackDecoder2::HandleControlFrameHeadersData(const char* headers_data,
71 size_t headers_data_length) {
72 DVLOG(2) << "HpackDecoder2::HandleControlFrameHeadersData: len="
73 << headers_data_length;
74 if (!header_block_started_) {
75 DCHECK_EQ(total_hpack_bytes_, 0u);
76 // Clear the SpdyHeaderBlock here rather than in Reset so that it is NOT
77 // cleared in HandleControlFrameHeadersComplete, which would be before it
78 // could be used.
79 decoded_block_.clear();
80 header_block_started_ = true;
81 if (handler_ != nullptr) {
82 handler_->OnHeaderBlockStart();
83 }
84 }
85
86 // Sometimes we get a call with headers_data==nullptr and
87 // headers_data_length==0, in which case we need to avoid creating
88 // a DecodeBuffer, which would otherwise complain.
89 if (headers_data_length > 0) {
90 DCHECK_NE(headers_data, nullptr);
91 total_hpack_bytes_ += headers_data_length;
92 DecodeBuffer db(headers_data, headers_data_length);
93 DecodeStatus status = hpack_block_decoder_.Decode(&db);
94 switch (status) {
95 case DecodeStatus::kDecodeDone:
96 // We've completed the decoding of headers_data, and it ended at the
97 // boundary between two HPACK block entries, so name_ and value_ are
98 // currently reset.
99 DCHECK_EQ(0u, db.Remaining());
100 in_progress_ = false;
101 break;
102
103 case DecodeStatus::kDecodeInProgress:
104 DCHECK_EQ(0u, db.Remaining());
105 in_progress_ = true;
106 if (!error_detected_) {
107 name_.BufferStringIfUnbuffered();
108 value_.BufferStringIfUnbuffered();
109 EnforceMaxDecodeBufferSize();
110 }
111 break;
112
113 case DecodeStatus::kDecodeError:
114 SetErrorDetected();
115 break;
116 }
117 }
118 return !error_detected_;
119 }
120
121 // Called after a HPACK block has been completely delivered via
122 // HandleControlFrameHeadersData(). Returns false if an error occurred.
123 // |compressed_len| if non-null will be set to the size of the encoded
124 // buffered block that was accumulated in HandleControlFrameHeadersData(),
125 // to support subsequent calculation of compression percentage.
126 // Discards the handler supplied at the start of decoding the block.
127 // TODO(jamessynge): Determine if compressed_len is needed; it is used to
128 // produce UUMA stat Net.SpdyHpackDecompressionPercentage, but only for
129 // SPDY3, not HTTP2.
130 bool HpackDecoder2::HandleControlFrameHeadersComplete(size_t* compressed_len) {
131 DVLOG(2) << "HpackDecoder2::HandleControlFrameHeadersComplete";
132 if (error_detected_ || in_progress_) {
133 DVLOG(2) << "error_detected_=" << error_detected_
134 << ", in_progress_=" << in_progress_;
135 return false;
136 }
137 if (compressed_len != nullptr) {
138 *compressed_len = total_hpack_bytes_;
139 }
140 if (handler_ != nullptr) {
141 handler_->OnHeaderBlockEnd(total_header_bytes_);
142 }
143 Reset();
144 return true;
145 }
146
147 const SpdyHeaderBlock& HpackDecoder2::decoded_block() const {
148 return decoded_block_;
149 }
150
151 void HpackDecoder2::SetHeaderTableDebugVisitor(
152 std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) {
153 DVLOG(2) << "HpackDecoder2::SetHeaderTableDebugVisitor";
154 header_table_.set_debug_visitor(std::move(visitor));
155 }
156
157 void HpackDecoder2::set_max_decode_buffer_size_bytes(
158 size_t max_decode_buffer_size_bytes) {
159 DVLOG(2) << "HpackDecoder2::set_max_decode_buffer_size_bytes";
160 max_decode_buffer_size_bytes_ = max_decode_buffer_size_bytes;
161 }
162
163 size_t HpackDecoder2::EstimateMemoryUsage() const {
164 return SpdyEstimateMemoryUsage(header_table_) +
165 SpdyEstimateMemoryUsage(decoded_block_) +
166 SpdyEstimateMemoryUsage(name_) + SpdyEstimateMemoryUsage(value_);
167 }
168
169 void HpackDecoder2::OnIndexedHeader(size_t index) {
170 DVLOG(2) << "HpackDecoder2::OnIndexedHeader: index=" << index;
171 DCHECK(!error_detected_);
172 const HpackEntry* entry = header_table_.GetByIndex(index);
173 if (entry == nullptr) {
174 SetErrorDetected();
175 return;
176 }
177 HandleHeaderRepresentation(entry->name(), entry->value());
178 }
179
180 void HpackDecoder2::OnStartLiteralHeader(HpackEntryType entry_type,
181 size_t maybe_name_index) {
182 DVLOG(2) << "HpackDecoder2::OnStartLiteralHeader: entry_type=" << entry_type
183 << ", maybe_name_index=" << maybe_name_index;
184 DCHECK(!error_detected_);
185 entry_type_ = entry_type;
186 if (maybe_name_index > 0) {
187 const HpackEntry* entry = header_table_.GetByIndex(maybe_name_index);
188 if (entry == nullptr) {
189 SetErrorDetected();
190 return;
191 } else {
192 // Non-static entries could be evicted, leaving us with a dangling
193 // pointer, so we preemptively copy. This could be avoided if
194 // TryAddEntry would copy the strings prior to performing eviction.
195 name_.Set(entry->name(), entry->IsStatic());
196 name_.BufferStringIfUnbuffered();
197 }
198 }
199 }
200
201 void HpackDecoder2::OnNameStart(bool huffman_encoded, size_t len) {
202 DVLOG(2) << "HpackDecoder2::OnNameStart: huffman_encoded="
203 << (huffman_encoded ? "true" : "false") << ", len=" << len;
204 if (len > max_decode_buffer_size_bytes_) {
205 DVLOG(1) << "Name length (" << len << ") is longer than permitted ("
206 << max_decode_buffer_size_bytes_ << ")";
207 SetErrorDetected();
208 return;
209 }
210 name_.OnStart(huffman_encoded, len);
211 }
212
213 void HpackDecoder2::OnNameData(const char* data, size_t len) {
214 DVLOG(2) << "HpackDecoder2::OnNameData: len=" << len
215 << "\n data: " << StringPiece(data, len);
216 if (error_detected_) {
217 return;
218 }
219 if (!name_.OnData(data, len)) {
220 SetErrorDetected();
221 }
222 }
223
224 void HpackDecoder2::OnNameEnd() {
225 DVLOG(2) << "HpackDecoder2::OnNameEnd";
226 if (error_detected_) {
227 return;
228 }
229 if (!name_.OnEnd()) {
230 SetErrorDetected();
231 }
232 }
233
234 void HpackDecoder2::OnValueStart(bool huffman_encoded, size_t len) {
235 DVLOG(2) << "HpackDecoder2::OnValueStart: huffman_encoded="
236 << (huffman_encoded ? "true" : "false") << ", len=" << len;
237 if (len > max_decode_buffer_size_bytes_) {
238 DVLOG(1) << "Value length (" << len << ") is longer than permitted ("
239 << max_decode_buffer_size_bytes_ << ")";
240 SetErrorDetected();
241 return;
242 }
243 value_.OnStart(huffman_encoded, len);
244 }
245
246 void HpackDecoder2::OnValueData(const char* data, size_t len) {
247 DVLOG(2) << "HpackDecoder2::OnValueData: len=" << len
248 << "\n data: " << StringPiece(data, len);
249 if (error_detected_) {
250 return;
251 }
252 if (!value_.OnData(data, len)) {
253 SetErrorDetected();
254 }
255 }
256
257 void HpackDecoder2::OnValueEnd() {
258 DVLOG(2) << "HpackDecoder2::OnValueEnd";
259 if (error_detected_) {
260 return;
261 }
262 if (!value_.OnEnd()) {
263 SetErrorDetected();
264 return;
265 }
266 if (EnforceMaxDecodeBufferSize()) {
267 // All is well.
268 HandleHeaderRepresentation(name_.str(), value_.str());
269 if (entry_type_ == HpackEntryType::kIndexedLiteralHeader) {
270 header_table_.TryAddEntry(name_.str(), value_.str());
271 }
272 name_.Reset();
273 value_.Reset();
274 }
275 }
276
277 void HpackDecoder2::OnDynamicTableSizeUpdate(size_t size) {
278 DVLOG(2) << "HpackDecoder2::OnDynamicTableSizeUpdate: size=" << size;
279 if (error_detected_) {
280 return;
281 }
282 if (size > header_table_.settings_size_bound()) {
283 DVLOG(1) << "Dynamic Table Size Update with too large a size: " << size
284 << " > " << header_table_.settings_size_bound();
285 SetErrorDetected();
286 return;
287 }
288 if (header_seen_) {
289 DVLOG(1) << "Dynamic Table Size Update seen after a Header";
290 SetErrorDetected();
291 return;
292 }
293 ++size_update_count_;
294 if (size_update_count_ > 2) {
295 DVLOG(1) << "Too many (" << size_update_count_
296 << ") Dynamic Table Size Updates";
297 SetErrorDetected();
298 return;
299 }
300 header_table_.SetMaxSize(size);
301 return;
302 }
303
304 bool HpackDecoder2::EnforceMaxDecodeBufferSize() {
305 if (!error_detected_) {
306 size_t buffered_length = name_.BufferedLength() + value_.BufferedLength();
307 DVLOG(2) << "buffered_length=" << buffered_length
308 << "; max=" << max_decode_buffer_size_bytes_;
309 if (buffered_length > max_decode_buffer_size_bytes_) {
310 DVLOG(1) << "Header length (" << buffered_length
311 << ") is longer than permitted ("
312 << max_decode_buffer_size_bytes_ << ")";
313 SetErrorDetected();
314 }
315 }
316 return !error_detected_;
317 }
318
319 void HpackDecoder2::HandleHeaderRepresentation(StringPiece name,
320 StringPiece value) {
321 DVLOG(2) << "HpackDecoder2::HandleHeaderRepresentation:\n name: " << name
322 << "\n value: " << value;
323 total_header_bytes_ += name.size() + value.size();
324 header_seen_ = true;
325 if (handler_ == nullptr) {
326 DVLOG(3) << "HpackDecoder2::HandleHeaderRepresentation "
327 << "adding to decoded_block";
328 decoded_block_.AppendValueOrAddHeader(name, value);
329 } else {
330 DVLOG(3) << "HpackDecoder2::HandleHeaderRepresentation "
331 << "passing to handler";
332 DCHECK(decoded_block_.empty());
333 handler_->OnHeader(name, value);
334 }
335 }
336
337 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/hpack/hpack_decoder2.h ('k') | net/spdy/hpack/hpack_decoder2_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698