1 // Copyright 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_instructions.h"
6
7 #include <limits>
8
9 #include "absl/strings/string_view.h"
10 #include "quiche/quic/platform/api/quic_logging.h"
11
12 namespace quic {
13
14 namespace {
15
16 // Validate that
17 // * in each instruction, the bits of |value| that are zero in |mask| are zero;
18 // * every byte matches exactly one opcode.
ValidateLangague(const QpackLanguage * language)19 void ValidateLangague(const QpackLanguage* language) {
20 #ifndef NDEBUG
21 for (const auto* instruction : *language) {
22 QUICHE_DCHECK_EQ(0, instruction->opcode.value & ~instruction->opcode.mask);
23 }
24
25 for (uint8_t byte = 0; byte < std::numeric_limits<uint8_t>::max(); ++byte) {
26 size_t match_count = 0;
27 for (const auto* instruction : *language) {
28 if ((byte & instruction->opcode.mask) == instruction->opcode.value) {
29 ++match_count;
30 }
31 }
32 QUICHE_DCHECK_EQ(1u, match_count) << static_cast<int>(byte);
33 }
34 #else
35 (void)language;
36 #endif
37 }
38
39 } // namespace
40
operator ==(const QpackInstructionOpcode & a,const QpackInstructionOpcode & b)41 bool operator==(const QpackInstructionOpcode& a,
42 const QpackInstructionOpcode& b) {
43 return std::tie(a.value, a.mask) == std::tie(b.value, b.mask);
44 }
45
InsertWithNameReferenceInstruction()46 const QpackInstruction* InsertWithNameReferenceInstruction() {
47 static const QpackInstructionOpcode* const opcode =
48 new QpackInstructionOpcode{0b10000000, 0b10000000};
49 static const QpackInstruction* const instruction =
50 new QpackInstruction{*opcode,
51 {{QpackInstructionFieldType::kSbit, 0b01000000},
52 {QpackInstructionFieldType::kVarint, 6},
53 {QpackInstructionFieldType::kValue, 7}}};
54 return instruction;
55 }
56
InsertWithoutNameReferenceInstruction()57 const QpackInstruction* InsertWithoutNameReferenceInstruction() {
58 static const QpackInstructionOpcode* const opcode =
59 new QpackInstructionOpcode{0b01000000, 0b11000000};
60 static const QpackInstruction* const instruction =
61 new QpackInstruction{*opcode,
62 {{QpackInstructionFieldType::kName, 5},
63 {QpackInstructionFieldType::kValue, 7}}};
64 return instruction;
65 }
66
DuplicateInstruction()67 const QpackInstruction* DuplicateInstruction() {
68 static const QpackInstructionOpcode* const opcode =
69 new QpackInstructionOpcode{0b00000000, 0b11100000};
70 static const QpackInstruction* const instruction =
71 new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 5}}};
72 return instruction;
73 }
74
SetDynamicTableCapacityInstruction()75 const QpackInstruction* SetDynamicTableCapacityInstruction() {
76 static const QpackInstructionOpcode* const opcode =
77 new QpackInstructionOpcode{0b00100000, 0b11100000};
78 static const QpackInstruction* const instruction =
79 new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 5}}};
80 return instruction;
81 }
82
QpackEncoderStreamLanguage()83 const QpackLanguage* QpackEncoderStreamLanguage() {
84 static const QpackLanguage* const language = new QpackLanguage{
85 InsertWithNameReferenceInstruction(),
86 InsertWithoutNameReferenceInstruction(), DuplicateInstruction(),
87 SetDynamicTableCapacityInstruction()};
88 ValidateLangague(language);
89 return language;
90 }
91
InsertCountIncrementInstruction()92 const QpackInstruction* InsertCountIncrementInstruction() {
93 static const QpackInstructionOpcode* const opcode =
94 new QpackInstructionOpcode{0b00000000, 0b11000000};
95 static const QpackInstruction* const instruction =
96 new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 6}}};
97 return instruction;
98 }
99
HeaderAcknowledgementInstruction()100 const QpackInstruction* HeaderAcknowledgementInstruction() {
101 static const QpackInstructionOpcode* const opcode =
102 new QpackInstructionOpcode{0b10000000, 0b10000000};
103 static const QpackInstruction* const instruction =
104 new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 7}}};
105 return instruction;
106 }
107
StreamCancellationInstruction()108 const QpackInstruction* StreamCancellationInstruction() {
109 static const QpackInstructionOpcode* const opcode =
110 new QpackInstructionOpcode{0b01000000, 0b11000000};
111 static const QpackInstruction* const instruction =
112 new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 6}}};
113 return instruction;
114 }
115
QpackDecoderStreamLanguage()116 const QpackLanguage* QpackDecoderStreamLanguage() {
117 static const QpackLanguage* const language = new QpackLanguage{
118 InsertCountIncrementInstruction(), HeaderAcknowledgementInstruction(),
119 StreamCancellationInstruction()};
120 ValidateLangague(language);
121 return language;
122 }
123
QpackPrefixInstruction()124 const QpackInstruction* QpackPrefixInstruction() {
125 // This opcode matches every input.
126 static const QpackInstructionOpcode* const opcode =
127 new QpackInstructionOpcode{0b00000000, 0b00000000};
128 static const QpackInstruction* const instruction =
129 new QpackInstruction{*opcode,
130 {{QpackInstructionFieldType::kVarint, 8},
131 {QpackInstructionFieldType::kSbit, 0b10000000},
132 {QpackInstructionFieldType::kVarint2, 7}}};
133 return instruction;
134 }
135
QpackPrefixLanguage()136 const QpackLanguage* QpackPrefixLanguage() {
137 static const QpackLanguage* const language =
138 new QpackLanguage{QpackPrefixInstruction()};
139 ValidateLangague(language);
140 return language;
141 }
142
QpackIndexedHeaderFieldInstruction()143 const QpackInstruction* QpackIndexedHeaderFieldInstruction() {
144 static const QpackInstructionOpcode* const opcode =
145 new QpackInstructionOpcode{0b10000000, 0b10000000};
146 static const QpackInstruction* const instruction =
147 new QpackInstruction{*opcode,
148 {{QpackInstructionFieldType::kSbit, 0b01000000},
149 {QpackInstructionFieldType::kVarint, 6}}};
150 return instruction;
151 }
152
QpackIndexedHeaderFieldPostBaseInstruction()153 const QpackInstruction* QpackIndexedHeaderFieldPostBaseInstruction() {
154 static const QpackInstructionOpcode* const opcode =
155 new QpackInstructionOpcode{0b00010000, 0b11110000};
156 static const QpackInstruction* const instruction =
157 new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 4}}};
158 return instruction;
159 }
160
QpackLiteralHeaderFieldNameReferenceInstruction()161 const QpackInstruction* QpackLiteralHeaderFieldNameReferenceInstruction() {
162 static const QpackInstructionOpcode* const opcode =
163 new QpackInstructionOpcode{0b01000000, 0b11000000};
164 static const QpackInstruction* const instruction =
165 new QpackInstruction{*opcode,
166 {{QpackInstructionFieldType::kSbit, 0b00010000},
167 {QpackInstructionFieldType::kVarint, 4},
168 {QpackInstructionFieldType::kValue, 7}}};
169 return instruction;
170 }
171
QpackLiteralHeaderFieldPostBaseInstruction()172 const QpackInstruction* QpackLiteralHeaderFieldPostBaseInstruction() {
173 static const QpackInstructionOpcode* const opcode =
174 new QpackInstructionOpcode{0b00000000, 0b11110000};
175 static const QpackInstruction* const instruction =
176 new QpackInstruction{*opcode,
177 {{QpackInstructionFieldType::kVarint, 3},
178 {QpackInstructionFieldType::kValue, 7}}};
179 return instruction;
180 }
181
QpackLiteralHeaderFieldInstruction()182 const QpackInstruction* QpackLiteralHeaderFieldInstruction() {
183 static const QpackInstructionOpcode* const opcode =
184 new QpackInstructionOpcode{0b00100000, 0b11100000};
185 static const QpackInstruction* const instruction =
186 new QpackInstruction{*opcode,
187 {{QpackInstructionFieldType::kName, 3},
188 {QpackInstructionFieldType::kValue, 7}}};
189 return instruction;
190 }
191
QpackRequestStreamLanguage()192 const QpackLanguage* QpackRequestStreamLanguage() {
193 static const QpackLanguage* const language =
194 new QpackLanguage{QpackIndexedHeaderFieldInstruction(),
195 QpackIndexedHeaderFieldPostBaseInstruction(),
196 QpackLiteralHeaderFieldNameReferenceInstruction(),
197 QpackLiteralHeaderFieldPostBaseInstruction(),
198 QpackLiteralHeaderFieldInstruction()};
199 ValidateLangague(language);
200 return language;
201 }
202
203 // static
InsertWithNameReference(bool is_static,uint64_t name_index,absl::string_view value)204 QpackInstructionWithValues QpackInstructionWithValues::InsertWithNameReference(
205 bool is_static, uint64_t name_index, absl::string_view value) {
206 QpackInstructionWithValues instruction_with_values;
207 instruction_with_values.instruction_ = InsertWithNameReferenceInstruction();
208 instruction_with_values.s_bit_ = is_static;
209 instruction_with_values.varint_ = name_index;
210 instruction_with_values.value_ = value;
211
212 return instruction_with_values;
213 }
214
215 // static
216 QpackInstructionWithValues
InsertWithoutNameReference(absl::string_view name,absl::string_view value)217 QpackInstructionWithValues::InsertWithoutNameReference(
218 absl::string_view name, absl::string_view value) {
219 QpackInstructionWithValues instruction_with_values;
220 instruction_with_values.instruction_ =
221 InsertWithoutNameReferenceInstruction();
222 instruction_with_values.name_ = name;
223 instruction_with_values.value_ = value;
224
225 return instruction_with_values;
226 }
227
228 // static
Duplicate(uint64_t index)229 QpackInstructionWithValues QpackInstructionWithValues::Duplicate(
230 uint64_t index) {
231 QpackInstructionWithValues instruction_with_values;
232 instruction_with_values.instruction_ = DuplicateInstruction();
233 instruction_with_values.varint_ = index;
234
235 return instruction_with_values;
236 }
237
238 // static
SetDynamicTableCapacity(uint64_t capacity)239 QpackInstructionWithValues QpackInstructionWithValues::SetDynamicTableCapacity(
240 uint64_t capacity) {
241 QpackInstructionWithValues instruction_with_values;
242 instruction_with_values.instruction_ = SetDynamicTableCapacityInstruction();
243 instruction_with_values.varint_ = capacity;
244
245 return instruction_with_values;
246 }
247
248 // static
InsertCountIncrement(uint64_t increment)249 QpackInstructionWithValues QpackInstructionWithValues::InsertCountIncrement(
250 uint64_t increment) {
251 QpackInstructionWithValues instruction_with_values;
252 instruction_with_values.instruction_ = InsertCountIncrementInstruction();
253 instruction_with_values.varint_ = increment;
254
255 return instruction_with_values;
256 }
257
258 // static
HeaderAcknowledgement(uint64_t stream_id)259 QpackInstructionWithValues QpackInstructionWithValues::HeaderAcknowledgement(
260 uint64_t stream_id) {
261 QpackInstructionWithValues instruction_with_values;
262 instruction_with_values.instruction_ = HeaderAcknowledgementInstruction();
263 instruction_with_values.varint_ = stream_id;
264
265 return instruction_with_values;
266 }
267
268 // static
StreamCancellation(uint64_t stream_id)269 QpackInstructionWithValues QpackInstructionWithValues::StreamCancellation(
270 uint64_t stream_id) {
271 QpackInstructionWithValues instruction_with_values;
272 instruction_with_values.instruction_ = StreamCancellationInstruction();
273 instruction_with_values.varint_ = stream_id;
274
275 return instruction_with_values;
276 }
277
278 // static
Prefix(uint64_t required_insert_count)279 QpackInstructionWithValues QpackInstructionWithValues::Prefix(
280 uint64_t required_insert_count) {
281 QpackInstructionWithValues instruction_with_values;
282 instruction_with_values.instruction_ = QpackPrefixInstruction();
283 instruction_with_values.varint_ = required_insert_count;
284 instruction_with_values.varint2_ = 0; // Delta Base.
285 instruction_with_values.s_bit_ = false; // Delta Base sign.
286
287 return instruction_with_values;
288 }
289
290 // static
IndexedHeaderField(bool is_static,uint64_t index)291 QpackInstructionWithValues QpackInstructionWithValues::IndexedHeaderField(
292 bool is_static, uint64_t index) {
293 QpackInstructionWithValues instruction_with_values;
294 instruction_with_values.instruction_ = QpackIndexedHeaderFieldInstruction();
295 instruction_with_values.s_bit_ = is_static;
296 instruction_with_values.varint_ = index;
297
298 return instruction_with_values;
299 }
300
301 // static
302 QpackInstructionWithValues
LiteralHeaderFieldNameReference(bool is_static,uint64_t index,absl::string_view value)303 QpackInstructionWithValues::LiteralHeaderFieldNameReference(
304 bool is_static, uint64_t index, absl::string_view value) {
305 QpackInstructionWithValues instruction_with_values;
306 instruction_with_values.instruction_ =
307 QpackLiteralHeaderFieldNameReferenceInstruction();
308 instruction_with_values.s_bit_ = is_static;
309 instruction_with_values.varint_ = index;
310 instruction_with_values.value_ = value;
311
312 return instruction_with_values;
313 }
314
315 // static
LiteralHeaderField(absl::string_view name,absl::string_view value)316 QpackInstructionWithValues QpackInstructionWithValues::LiteralHeaderField(
317 absl::string_view name, absl::string_view value) {
318 QpackInstructionWithValues instruction_with_values;
319 instruction_with_values.instruction_ = QpackLiteralHeaderFieldInstruction();
320 instruction_with_values.name_ = name;
321 instruction_with_values.value_ = value;
322
323 return instruction_with_values;
324 }
325
326 } // namespace quic
327