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