• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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