1 // 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 "quiche/quic/core/qpack/qpack_decoder.h"
6
7 #include <utility>
8
9 #include "absl/strings/string_view.h"
10 #include "quiche/quic/core/qpack/qpack_index_conversions.h"
11 #include "quiche/quic/platform/api/quic_flag_utils.h"
12 #include "quiche/quic/platform/api/quic_flags.h"
13 #include "quiche/quic/platform/api/quic_logging.h"
14
15 namespace quic {
16
QpackDecoder(uint64_t maximum_dynamic_table_capacity,uint64_t maximum_blocked_streams,EncoderStreamErrorDelegate * encoder_stream_error_delegate)17 QpackDecoder::QpackDecoder(
18 uint64_t maximum_dynamic_table_capacity, uint64_t maximum_blocked_streams,
19 EncoderStreamErrorDelegate* encoder_stream_error_delegate)
20 : encoder_stream_error_delegate_(encoder_stream_error_delegate),
21 encoder_stream_receiver_(this),
22 maximum_blocked_streams_(maximum_blocked_streams),
23 known_received_count_(0) {
24 QUICHE_DCHECK(encoder_stream_error_delegate_);
25
26 header_table_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
27 }
28
~QpackDecoder()29 QpackDecoder::~QpackDecoder() {}
30
OnStreamReset(QuicStreamId stream_id)31 void QpackDecoder::OnStreamReset(QuicStreamId stream_id) {
32 if (header_table_.maximum_dynamic_table_capacity() > 0) {
33 decoder_stream_sender_.SendStreamCancellation(stream_id);
34 decoder_stream_sender_.Flush();
35 }
36 }
37
OnStreamBlocked(QuicStreamId stream_id)38 bool QpackDecoder::OnStreamBlocked(QuicStreamId stream_id) {
39 auto result = blocked_streams_.insert(stream_id);
40 QUICHE_DCHECK(result.second);
41 return blocked_streams_.size() <= maximum_blocked_streams_;
42 }
43
OnStreamUnblocked(QuicStreamId stream_id)44 void QpackDecoder::OnStreamUnblocked(QuicStreamId stream_id) {
45 size_t result = blocked_streams_.erase(stream_id);
46 QUICHE_DCHECK_EQ(1u, result);
47 }
48
OnDecodingCompleted(QuicStreamId stream_id,uint64_t required_insert_count)49 void QpackDecoder::OnDecodingCompleted(QuicStreamId stream_id,
50 uint64_t required_insert_count) {
51 if (required_insert_count > 0) {
52 decoder_stream_sender_.SendHeaderAcknowledgement(stream_id);
53
54 if (known_received_count_ < required_insert_count) {
55 known_received_count_ = required_insert_count;
56 }
57 }
58
59 // Send an Insert Count Increment instruction if not all dynamic table entries
60 // have been acknowledged yet. This is necessary for efficient compression in
61 // case the encoder chooses not to reference unacknowledged dynamic table
62 // entries, otherwise inserted entries would never be acknowledged.
63 if (known_received_count_ < header_table_.inserted_entry_count()) {
64 decoder_stream_sender_.SendInsertCountIncrement(
65 header_table_.inserted_entry_count() - known_received_count_);
66 known_received_count_ = header_table_.inserted_entry_count();
67 }
68
69 decoder_stream_sender_.Flush();
70 }
71
OnInsertWithNameReference(bool is_static,uint64_t name_index,absl::string_view value)72 void QpackDecoder::OnInsertWithNameReference(bool is_static,
73 uint64_t name_index,
74 absl::string_view value) {
75 if (is_static) {
76 auto entry = header_table_.LookupEntry(/* is_static = */ true, name_index);
77 if (!entry) {
78 OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_INVALID_STATIC_ENTRY,
79 "Invalid static table entry.");
80 return;
81 }
82
83 if (!header_table_.EntryFitsDynamicTableCapacity(entry->name(), value)) {
84 OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_ERROR_INSERTING_STATIC,
85 "Error inserting entry with name reference.");
86 return;
87 }
88 header_table_.InsertEntry(entry->name(), value);
89 return;
90 }
91
92 uint64_t absolute_index;
93 if (!QpackEncoderStreamRelativeIndexToAbsoluteIndex(
94 name_index, header_table_.inserted_entry_count(), &absolute_index)) {
95 OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_INSERTION_INVALID_RELATIVE_INDEX,
96 "Invalid relative index.");
97 return;
98 }
99
100 const QpackEntry* entry =
101 header_table_.LookupEntry(/* is_static = */ false, absolute_index);
102 if (!entry) {
103 OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_INSERTION_DYNAMIC_ENTRY_NOT_FOUND,
104 "Dynamic table entry not found.");
105 return;
106 }
107 if (!header_table_.EntryFitsDynamicTableCapacity(entry->name(), value)) {
108 OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_ERROR_INSERTING_DYNAMIC,
109 "Error inserting entry with name reference.");
110 return;
111 }
112 header_table_.InsertEntry(entry->name(), value);
113 }
114
OnInsertWithoutNameReference(absl::string_view name,absl::string_view value)115 void QpackDecoder::OnInsertWithoutNameReference(absl::string_view name,
116 absl::string_view value) {
117 if (!header_table_.EntryFitsDynamicTableCapacity(name, value)) {
118 OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_ERROR_INSERTING_LITERAL,
119 "Error inserting literal entry.");
120 return;
121 }
122 header_table_.InsertEntry(name, value);
123 }
124
OnDuplicate(uint64_t index)125 void QpackDecoder::OnDuplicate(uint64_t index) {
126 uint64_t absolute_index;
127 if (!QpackEncoderStreamRelativeIndexToAbsoluteIndex(
128 index, header_table_.inserted_entry_count(), &absolute_index)) {
129 OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_DUPLICATE_INVALID_RELATIVE_INDEX,
130 "Invalid relative index.");
131 return;
132 }
133
134 const QpackEntry* entry =
135 header_table_.LookupEntry(/* is_static = */ false, absolute_index);
136 if (!entry) {
137 OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_DUPLICATE_DYNAMIC_ENTRY_NOT_FOUND,
138 "Dynamic table entry not found.");
139 return;
140 }
141 if (!header_table_.EntryFitsDynamicTableCapacity(entry->name(),
142 entry->value())) {
143 // This is impossible since entry was retrieved from the dynamic table.
144 OnErrorDetected(QUIC_INTERNAL_ERROR, "Error inserting duplicate entry.");
145 return;
146 }
147 header_table_.InsertEntry(entry->name(), entry->value());
148 }
149
OnSetDynamicTableCapacity(uint64_t capacity)150 void QpackDecoder::OnSetDynamicTableCapacity(uint64_t capacity) {
151 if (!header_table_.SetDynamicTableCapacity(capacity)) {
152 OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_SET_DYNAMIC_TABLE_CAPACITY,
153 "Error updating dynamic table capacity.");
154 }
155 }
156
OnErrorDetected(QuicErrorCode error_code,absl::string_view error_message)157 void QpackDecoder::OnErrorDetected(QuicErrorCode error_code,
158 absl::string_view error_message) {
159 encoder_stream_error_delegate_->OnEncoderStreamError(error_code,
160 error_message);
161 }
162
CreateProgressiveDecoder(QuicStreamId stream_id,QpackProgressiveDecoder::HeadersHandlerInterface * handler)163 std::unique_ptr<QpackProgressiveDecoder> QpackDecoder::CreateProgressiveDecoder(
164 QuicStreamId stream_id,
165 QpackProgressiveDecoder::HeadersHandlerInterface* handler) {
166 return std::make_unique<QpackProgressiveDecoder>(stream_id, this, this,
167 &header_table_, handler);
168 }
169
170 } // namespace quic
171