in proxygen/lib/http/codec/compress/QPACKEncoder.cpp [105:192]
size_t QPACKEncoder::encodeHeaderQ(HPACKHeaderName name,
folly::StringPiece value,
uint32_t baseIndex,
uint32_t& requiredInsertCount) {
size_t uncompressed = HPACKHeader::realBytes(name.size(), value.size()) + 2;
uint32_t index = getStaticTable().getIndex(name, value);
if (index > 0) {
// static reference
staticRefs_++;
streamBuffer_.encodeInteger(index - 1,
HPACK::Q_INDEXED.code | HPACK::Q_INDEXED_STATIC,
HPACK::Q_INDEXED.prefixLength);
return uncompressed;
}
bool indexable = shouldIndex(name, value);
if (indexable) {
index = table_.getIndex(name, value, allowVulnerable());
if (index == QPACKHeaderTable::UNACKED) {
index = 0;
indexable = false;
}
}
if (index != 0) {
// dynamic reference
bool duplicated = false;
std::tie(duplicated, index) = maybeDuplicate(index);
// index is now 0 or absolute
indexable &= (duplicated && index == 0);
}
if (index == 0) {
// No valid entry matching header, see if there's a matching name
uint32_t nameIndex = 0;
uint32_t absoluteNameIndex = 0;
bool isStaticName = false;
std::tie(isStaticName, nameIndex, absoluteNameIndex) = getNameIndexQ(name);
// Now check if we should emit an insertion on the control stream
// Don't try to index if we're out of encoder flow control
indexable &= maxEncoderStreamBytes_ > 0;
if (indexable) {
if (table_.canIndex(name, value)) {
encodeInsertQ(name, value, isStaticName, nameIndex);
CHECK(table_.add(HPACKHeader(std::move(name), value)));
if (allowVulnerable() && lastEntryAvailable()) {
index = table_.getInsertCount();
// name is invalid on this branch, but index must be non-zero since
// we inserted just above.
} else {
// We still need name. Get it from the table
name = getHeader(false, 1, table_.getInsertCount(), false).name;
index = 0;
if (absoluteNameIndex > 0 &&
!table_.isValid(table_.absoluteToRelative(absoluteNameIndex))) {
// The insert may have invalidated the name index.
isStaticName = true;
nameIndex = 0;
absoluteNameIndex = 0;
}
}
} else {
blockedInsertions_++;
}
}
if (index == 0) {
// Couldn't insert it: table full, not indexable, or table contains
// vulnerable reference. Encode a literal on the request stream.
encodeStreamLiteralQ(name,
value,
isStaticName,
nameIndex,
absoluteNameIndex,
baseIndex,
requiredInsertCount);
return uncompressed;
}
}
// Encoding a dynamic index reference
DCHECK_NE(index, 0);
trackReference(index, requiredInsertCount);
if (index > baseIndex) {
streamBuffer_.encodeInteger(index - baseIndex - 1, HPACK::Q_INDEXED_POST);
} else {
streamBuffer_.encodeInteger(baseIndex - index, HPACK::Q_INDEXED);
}
return uncompressed;
}