size_t QPACKEncoder::encodeHeaderQ()

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;
}