blob: 1e5d1124c57fa5b92d783efaafbaebcd2169b94b [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
#include <limits>
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace quic {
namespace {
// Validate that
// * in each instruction, the bits of |value| that are zero in |mask| are zero;
// * every byte matches exactly one opcode.
void ValidateLangague(const QpackLanguage* language) {
#ifndef NDEBUG
for (const auto* instruction : *language) {
DCHECK_EQ(0, instruction->opcode.value & ~instruction->opcode.mask);
}
for (uint8_t byte = 0; byte < std::numeric_limits<uint8_t>::max(); ++byte) {
size_t match_count = 0;
for (const auto* instruction : *language) {
if ((byte & instruction->opcode.mask) == instruction->opcode.value) {
++match_count;
}
}
DCHECK_EQ(1u, match_count) << static_cast<int>(byte);
}
#else
(void)language;
#endif
}
} // namespace
bool operator==(const QpackInstructionOpcode& a,
const QpackInstructionOpcode& b) {
return std::tie(a.value, a.mask) == std::tie(b.value, b.mask);
}
const QpackInstruction* InsertWithNameReferenceInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b10000000, 0b10000000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode,
{{QpackInstructionFieldType::kSbit, 0b01000000},
{QpackInstructionFieldType::kVarint, 6},
{QpackInstructionFieldType::kValue, 7}}};
return instruction;
}
const QpackInstruction* InsertWithoutNameReferenceInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b01000000, 0b11000000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode,
{{QpackInstructionFieldType::kName, 5},
{QpackInstructionFieldType::kValue, 7}}};
return instruction;
}
const QpackInstruction* DuplicateInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b00000000, 0b11100000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 5}}};
return instruction;
}
const QpackInstruction* SetDynamicTableCapacityInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b00100000, 0b11100000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 5}}};
return instruction;
}
const QpackLanguage* QpackEncoderStreamLanguage() {
static const QpackLanguage* const language = new QpackLanguage{
InsertWithNameReferenceInstruction(),
InsertWithoutNameReferenceInstruction(), DuplicateInstruction(),
SetDynamicTableCapacityInstruction()};
ValidateLangague(language);
return language;
}
const QpackInstruction* InsertCountIncrementInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b00000000, 0b11000000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 6}}};
return instruction;
}
const QpackInstruction* HeaderAcknowledgementInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b10000000, 0b10000000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 7}}};
return instruction;
}
const QpackInstruction* StreamCancellationInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b01000000, 0b11000000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 6}}};
return instruction;
}
const QpackLanguage* QpackDecoderStreamLanguage() {
static const QpackLanguage* const language = new QpackLanguage{
InsertCountIncrementInstruction(), HeaderAcknowledgementInstruction(),
StreamCancellationInstruction()};
ValidateLangague(language);
return language;
}
const QpackInstruction* QpackPrefixInstruction() {
// This opcode matches every input.
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b00000000, 0b00000000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode,
{{QpackInstructionFieldType::kVarint, 8},
{QpackInstructionFieldType::kSbit, 0b10000000},
{QpackInstructionFieldType::kVarint2, 7}}};
return instruction;
}
const QpackLanguage* QpackPrefixLanguage() {
static const QpackLanguage* const language =
new QpackLanguage{QpackPrefixInstruction()};
ValidateLangague(language);
return language;
}
const QpackInstruction* QpackIndexedHeaderFieldInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b10000000, 0b10000000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode,
{{QpackInstructionFieldType::kSbit, 0b01000000},
{QpackInstructionFieldType::kVarint, 6}}};
return instruction;
}
const QpackInstruction* QpackIndexedHeaderFieldPostBaseInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b00010000, 0b11110000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode, {{QpackInstructionFieldType::kVarint, 4}}};
return instruction;
}
const QpackInstruction* QpackLiteralHeaderFieldNameReferenceInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b01000000, 0b11000000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode,
{{QpackInstructionFieldType::kSbit, 0b00010000},
{QpackInstructionFieldType::kVarint, 4},
{QpackInstructionFieldType::kValue, 7}}};
return instruction;
}
const QpackInstruction* QpackLiteralHeaderFieldPostBaseInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b00000000, 0b11110000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode,
{{QpackInstructionFieldType::kVarint, 3},
{QpackInstructionFieldType::kValue, 7}}};
return instruction;
}
const QpackInstruction* QpackLiteralHeaderFieldInstruction() {
static const QpackInstructionOpcode* const opcode =
new QpackInstructionOpcode{0b00100000, 0b11100000};
static const QpackInstruction* const instruction =
new QpackInstruction{*opcode,
{{QpackInstructionFieldType::kName, 3},
{QpackInstructionFieldType::kValue, 7}}};
return instruction;
}
const QpackLanguage* QpackRequestStreamLanguage() {
static const QpackLanguage* const language =
new QpackLanguage{QpackIndexedHeaderFieldInstruction(),
QpackIndexedHeaderFieldPostBaseInstruction(),
QpackLiteralHeaderFieldNameReferenceInstruction(),
QpackLiteralHeaderFieldPostBaseInstruction(),
QpackLiteralHeaderFieldInstruction()};
ValidateLangague(language);
return language;
}
// static
QpackInstructionWithValues QpackInstructionWithValues::InsertWithNameReference(
bool is_static,
uint64_t name_index,
quiche::QuicheStringPiece value) {
QpackInstructionWithValues instruction_with_values;
instruction_with_values.instruction_ = InsertWithNameReferenceInstruction();
instruction_with_values.s_bit_ = is_static;
instruction_with_values.varint_ = name_index;
instruction_with_values.value_ = value;
return instruction_with_values;
}
// static
QpackInstructionWithValues
QpackInstructionWithValues::InsertWithoutNameReference(
quiche::QuicheStringPiece name,
quiche::QuicheStringPiece value) {
QpackInstructionWithValues instruction_with_values;
instruction_with_values.instruction_ =
InsertWithoutNameReferenceInstruction();
instruction_with_values.name_ = name;
instruction_with_values.value_ = value;
return instruction_with_values;
}
// static
QpackInstructionWithValues QpackInstructionWithValues::Duplicate(
uint64_t index) {
QpackInstructionWithValues instruction_with_values;
instruction_with_values.instruction_ = DuplicateInstruction();
instruction_with_values.varint_ = index;
return instruction_with_values;
}
// static
QpackInstructionWithValues QpackInstructionWithValues::SetDynamicTableCapacity(
uint64_t capacity) {
QpackInstructionWithValues instruction_with_values;
instruction_with_values.instruction_ = SetDynamicTableCapacityInstruction();
instruction_with_values.varint_ = capacity;
return instruction_with_values;
}
// static
QpackInstructionWithValues QpackInstructionWithValues::InsertCountIncrement(
uint64_t increment) {
QpackInstructionWithValues instruction_with_values;
instruction_with_values.instruction_ = InsertCountIncrementInstruction();
instruction_with_values.varint_ = increment;
return instruction_with_values;
}
// static
QpackInstructionWithValues QpackInstructionWithValues::HeaderAcknowledgement(
uint64_t stream_id) {
QpackInstructionWithValues instruction_with_values;
instruction_with_values.instruction_ = HeaderAcknowledgementInstruction();
instruction_with_values.varint_ = stream_id;
return instruction_with_values;
}
// static
QpackInstructionWithValues QpackInstructionWithValues::StreamCancellation(
uint64_t stream_id) {
QpackInstructionWithValues instruction_with_values;
instruction_with_values.instruction_ = StreamCancellationInstruction();
instruction_with_values.varint_ = stream_id;
return instruction_with_values;
}
// static
QpackInstructionWithValues QpackInstructionWithValues::Prefix(
uint64_t required_insert_count) {
QpackInstructionWithValues instruction_with_values;
instruction_with_values.instruction_ = QpackPrefixInstruction();
instruction_with_values.varint_ = required_insert_count;
instruction_with_values.varint2_ = 0; // Delta Base.
instruction_with_values.s_bit_ = false; // Delta Base sign.
return instruction_with_values;
}
// static
QpackInstructionWithValues QpackInstructionWithValues::IndexedHeaderField(
bool is_static,
uint64_t index) {
QpackInstructionWithValues instruction_with_values;
instruction_with_values.instruction_ = QpackIndexedHeaderFieldInstruction();
instruction_with_values.s_bit_ = is_static;
instruction_with_values.varint_ = index;
return instruction_with_values;
}
// static
QpackInstructionWithValues
QpackInstructionWithValues::LiteralHeaderFieldNameReference(
bool is_static,
uint64_t index,
quiche::QuicheStringPiece value) {
QpackInstructionWithValues instruction_with_values;
instruction_with_values.instruction_ =
QpackLiteralHeaderFieldNameReferenceInstruction();
instruction_with_values.s_bit_ = is_static;
instruction_with_values.varint_ = index;
instruction_with_values.value_ = value;
return instruction_with_values;
}
// static
QpackInstructionWithValues QpackInstructionWithValues::LiteralHeaderField(
quiche::QuicheStringPiece name,
quiche::QuicheStringPiece value) {
QpackInstructionWithValues instruction_with_values;
instruction_with_values.instruction_ = QpackLiteralHeaderFieldInstruction();
instruction_with_values.name_ = name;
instruction_with_values.value_ = value;
return instruction_with_values;
}
} // namespace quic