blob: 430e707726a60638a5ac46fefd0735bc5391308d [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2018 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/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h"
6
7#include <algorithm>
8#include <limits>
9
10#include "base/logging.h"
11#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
12#include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
14
15namespace quic {
16
17QpackProgressiveDecoder::QpackProgressiveDecoder(
18 QuicStreamId stream_id,
19 QpackHeaderTable* header_table,
20 QpackDecoderStreamSender* decoder_stream_sender,
21 HeadersHandlerInterface* handler)
22 : stream_id_(stream_id),
23 prefix_decoder_(
24 QuicMakeUnique<QpackInstructionDecoder>(QpackPrefixLanguage(), this)),
25 instruction_decoder_(QpackRequestStreamLanguage(), this),
26 header_table_(header_table),
27 decoder_stream_sender_(decoder_stream_sender),
28 handler_(handler),
29 required_insert_count_(0),
30 base_(0),
31 required_insert_count_so_far_(0),
32 prefix_decoded_(false),
33 decoding_(true),
34 error_detected_(false) {}
35
36// static
37bool QpackProgressiveDecoder::DecodeRequiredInsertCount(
38 uint64_t encoded_required_insert_count,
39 uint64_t max_entries,
40 uint64_t total_number_of_inserts,
41 uint64_t* required_insert_count) {
42 if (encoded_required_insert_count == 0) {
43 *required_insert_count = 0;
44 return true;
45 }
46
47 // |max_entries| is calculated by dividing an unsigned 64-bit integer by 32,
48 // precluding all calculations in this method from overflowing.
49 DCHECK_LE(max_entries, std::numeric_limits<uint64_t>::max() / 32);
50
51 if (encoded_required_insert_count > 2 * max_entries) {
52 return false;
53 }
54
55 *required_insert_count = encoded_required_insert_count - 1;
56 DCHECK_LT(*required_insert_count, std::numeric_limits<uint64_t>::max() / 16);
57
58 uint64_t current_wrapped = total_number_of_inserts % (2 * max_entries);
59 DCHECK_LT(current_wrapped, std::numeric_limits<uint64_t>::max() / 16);
60
61 if (current_wrapped >= *required_insert_count + max_entries) {
62 // Required Insert Count wrapped around 1 extra time.
63 *required_insert_count += 2 * max_entries;
64 } else if (current_wrapped + max_entries < *required_insert_count) {
65 // Decoder wrapped around 1 extra time.
66 current_wrapped += 2 * max_entries;
67 }
68
69 if (*required_insert_count >
70 std::numeric_limits<uint64_t>::max() - total_number_of_inserts) {
71 return false;
72 }
73
74 *required_insert_count += total_number_of_inserts;
75
76 // Prevent underflow, also disallow invalid value 0 for Required Insert Count.
77 if (current_wrapped >= *required_insert_count) {
78 return false;
79 }
80
81 *required_insert_count -= current_wrapped;
82
83 return true;
84}
85
86void QpackProgressiveDecoder::Decode(QuicStringPiece data) {
87 DCHECK(decoding_);
88
89 if (data.empty() || error_detected_) {
90 return;
91 }
92
93 // Decode prefix byte by byte until the first (and only) instruction is
94 // decoded.
95 while (!prefix_decoded_) {
96 prefix_decoder_->Decode(data.substr(0, 1));
97 data = data.substr(1);
98 if (data.empty()) {
99 return;
100 }
101 }
102
103 instruction_decoder_.Decode(data);
104}
105
106void QpackProgressiveDecoder::EndHeaderBlock() {
107 DCHECK(decoding_);
108 decoding_ = false;
109
110 if (error_detected_) {
111 return;
112 }
113
114 if (!instruction_decoder_.AtInstructionBoundary()) {
115 OnError("Incomplete header block.");
116 return;
117 }
118
119 if (!prefix_decoded_) {
120 OnError("Incomplete header data prefix.");
121 return;
122 }
123
124 if (required_insert_count_ != required_insert_count_so_far_) {
125 OnError("Required Insert Count too large.");
126 return;
127 }
128
129 decoder_stream_sender_->SendHeaderAcknowledgement(stream_id_);
130 handler_->OnDecodingCompleted();
131}
132
133bool QpackProgressiveDecoder::OnInstructionDecoded(
134 const QpackInstruction* instruction) {
135 if (instruction == QpackIndexedHeaderFieldInstruction()) {
136 return DoIndexedHeaderFieldInstruction();
137 }
138 if (instruction == QpackIndexedHeaderFieldPostBaseInstruction()) {
139 return DoIndexedHeaderFieldPostBaseInstruction();
140 }
141 if (instruction == QpackLiteralHeaderFieldNameReferenceInstruction()) {
142 return DoLiteralHeaderFieldNameReferenceInstruction();
143 }
144 if (instruction == QpackLiteralHeaderFieldPostBaseInstruction()) {
145 return DoLiteralHeaderFieldPostBaseInstruction();
146 }
147 if (instruction == QpackLiteralHeaderFieldInstruction()) {
148 return DoLiteralHeaderFieldInstruction();
149 }
150 DCHECK_EQ(instruction, QpackPrefixInstruction());
151 return DoPrefixInstruction();
152}
153
154void QpackProgressiveDecoder::OnError(QuicStringPiece error_message) {
155 DCHECK(!error_detected_);
156
157 error_detected_ = true;
158 handler_->OnDecodingErrorDetected(error_message);
159}
160
161bool QpackProgressiveDecoder::DoIndexedHeaderFieldInstruction() {
162 if (!instruction_decoder_.s_bit()) {
163 uint64_t absolute_index;
164 if (!RequestStreamRelativeIndexToAbsoluteIndex(
165 instruction_decoder_.varint(), &absolute_index)) {
166 OnError("Invalid relative index.");
167 return false;
168 }
169
170 if (absolute_index >= required_insert_count_) {
171 OnError("Absolute Index must be smaller than Required Insert Count.");
172 return false;
173 }
174
175 DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
176 required_insert_count_so_far_ =
177 std::max(required_insert_count_so_far_, absolute_index + 1);
178
179 auto entry =
180 header_table_->LookupEntry(/* is_static = */ false, absolute_index);
181 if (!entry) {
182 OnError("Dynamic table entry not found.");
183 return false;
184 }
185
186 handler_->OnHeaderDecoded(entry->name(), entry->value());
187 return true;
188 }
189
190 auto entry = header_table_->LookupEntry(/* is_static = */ true,
191 instruction_decoder_.varint());
192 if (!entry) {
193 OnError("Static table entry not found.");
194 return false;
195 }
196
197 handler_->OnHeaderDecoded(entry->name(), entry->value());
198 return true;
199}
200
201bool QpackProgressiveDecoder::DoIndexedHeaderFieldPostBaseInstruction() {
202 uint64_t absolute_index;
203 if (!PostBaseIndexToAbsoluteIndex(instruction_decoder_.varint(),
204 &absolute_index)) {
205 OnError("Invalid post-base index.");
206 return false;
207 }
208
209 if (absolute_index >= required_insert_count_) {
210 OnError("Absolute Index must be smaller than Required Insert Count.");
211 return false;
212 }
213
214 DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
215 required_insert_count_so_far_ =
216 std::max(required_insert_count_so_far_, absolute_index + 1);
217
218 auto entry =
219 header_table_->LookupEntry(/* is_static = */ false, absolute_index);
220 if (!entry) {
221 OnError("Dynamic table entry not found.");
222 return false;
223 }
224
225 handler_->OnHeaderDecoded(entry->name(), entry->value());
226 return true;
227}
228
229bool QpackProgressiveDecoder::DoLiteralHeaderFieldNameReferenceInstruction() {
230 if (!instruction_decoder_.s_bit()) {
231 uint64_t absolute_index;
232 if (!RequestStreamRelativeIndexToAbsoluteIndex(
233 instruction_decoder_.varint(), &absolute_index)) {
234 OnError("Invalid relative index.");
235 return false;
236 }
237
238 if (absolute_index >= required_insert_count_) {
239 OnError("Absolute Index must be smaller than Required Insert Count.");
240 return false;
241 }
242
243 DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
244 required_insert_count_so_far_ =
245 std::max(required_insert_count_so_far_, absolute_index + 1);
246
247 auto entry =
248 header_table_->LookupEntry(/* is_static = */ false, absolute_index);
249 if (!entry) {
250 OnError("Dynamic table entry not found.");
251 return false;
252 }
253
254 handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value());
255 return true;
256 }
257
258 auto entry = header_table_->LookupEntry(/* is_static = */ true,
259 instruction_decoder_.varint());
260 if (!entry) {
261 OnError("Static table entry not found.");
262 return false;
263 }
264
265 handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value());
266 return true;
267}
268
269bool QpackProgressiveDecoder::DoLiteralHeaderFieldPostBaseInstruction() {
270 uint64_t absolute_index;
271 if (!PostBaseIndexToAbsoluteIndex(instruction_decoder_.varint(),
272 &absolute_index)) {
273 OnError("Invalid post-base index.");
274 return false;
275 }
276
277 if (absolute_index >= required_insert_count_) {
278 OnError("Absolute Index must be smaller than Required Insert Count.");
279 return false;
280 }
281
282 DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
283 required_insert_count_so_far_ =
284 std::max(required_insert_count_so_far_, absolute_index + 1);
285
286 auto entry =
287 header_table_->LookupEntry(/* is_static = */ false, absolute_index);
288 if (!entry) {
289 OnError("Dynamic table entry not found.");
290 return false;
291 }
292
293 handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value());
294 return true;
295}
296
297bool QpackProgressiveDecoder::DoLiteralHeaderFieldInstruction() {
298 handler_->OnHeaderDecoded(instruction_decoder_.name(),
299 instruction_decoder_.value());
300
301 return true;
302}
303
304bool QpackProgressiveDecoder::DoPrefixInstruction() {
305 DCHECK(!prefix_decoded_);
306
307 if (!DecodeRequiredInsertCount(
308 prefix_decoder_->varint(), header_table_->max_entries(),
309 header_table_->inserted_entry_count(), &required_insert_count_)) {
310 OnError("Error decoding Required Insert Count.");
311 return false;
312 }
313
314 const bool sign = prefix_decoder_->s_bit();
315 const uint64_t delta_base = prefix_decoder_->varint2();
316 if (!DeltaBaseToBase(sign, delta_base, &base_)) {
317 OnError("Error calculating Base.");
318 return false;
319 }
320
321 prefix_decoded_ = true;
322
323 return true;
324}
325
326bool QpackProgressiveDecoder::DeltaBaseToBase(bool sign,
327 uint64_t delta_base,
328 uint64_t* base) {
329 if (sign) {
330 if (delta_base == std::numeric_limits<uint64_t>::max() ||
331 required_insert_count_ < delta_base + 1) {
332 return false;
333 }
334 *base = required_insert_count_ - delta_base - 1;
335 return true;
336 }
337
338 if (delta_base >
339 std::numeric_limits<uint64_t>::max() - required_insert_count_) {
340 return false;
341 }
342 *base = required_insert_count_ + delta_base;
343 return true;
344}
345
346bool QpackProgressiveDecoder::RequestStreamRelativeIndexToAbsoluteIndex(
347 uint64_t relative_index,
348 uint64_t* absolute_index) const {
349 if (relative_index == std::numeric_limits<uint64_t>::max() ||
350 relative_index + 1 > base_) {
351 return false;
352 }
353
354 *absolute_index = base_ - 1 - relative_index;
355 return true;
356}
357
358bool QpackProgressiveDecoder::PostBaseIndexToAbsoluteIndex(
359 uint64_t post_base_index,
360 uint64_t* absolute_index) const {
361 if (post_base_index >= std::numeric_limits<uint64_t>::max() - base_) {
362 return false;
363 }
364
365 *absolute_index = base_ + post_base_index;
366 return true;
367}
368
369} // namespace quic