uint32_t QPACKDecoder::decodePrefix()

in proxygen/lib/http/codec/compress/QPACKDecoder.cpp [55:128]


uint32_t QPACKDecoder::decodePrefix(HPACKDecodeBuffer& dbuf) {
  uint64_t requiredInsertCount;
  uint64_t wireRIC;
  uint64_t maxEntries = getMaxEntries(maxTableSize_);
  uint64_t fullRange = 2 * maxEntries;

  err_ = dbuf.decodeInteger(wireRIC);
  if (err_ != HPACK::DecodeError::NONE) {
    LOG(ERROR) << "Decode error decoding requiredInsertCount err_=" << err_;
    return 0;
  }
  if (wireRIC == 0) {
    requiredInsertCount = 0;
  } else if (maxEntries == 0) {
    LOG(ERROR) << "Encoder used dynamic table when not permitted, wireRIC="
               << wireRIC;
    err_ = HPACK::DecodeError::INVALID_INDEX;
    return 0;
  } else {
    uint64_t maxValue = table_.getInsertCount() + maxEntries;
    uint64_t maxWrapped = (maxValue / fullRange) * fullRange;
    requiredInsertCount = maxWrapped + wireRIC - 1;
    // If requiredInsertCount exceeds maxValue, the Encoder's value must have
    // wrapped one fewer time
    if (requiredInsertCount > maxValue) {
      if (wireRIC > fullRange || requiredInsertCount < fullRange) {
        LOG(ERROR) << "Decode error RIC out of range=" << wireRIC;
        err_ = HPACK::DecodeError::INVALID_INDEX;
        return 0;
      }
      requiredInsertCount -= fullRange;
    }
  }
  VLOG(5) << "Decoded requiredInsertCount=" << requiredInsertCount;
  uint64_t delta = 0;
  if (dbuf.empty()) {
    LOG(ERROR) << "Invalid prefix, no delta-base";
    err_ = HPACK::DecodeError::BUFFER_UNDERFLOW;
    return 0;
  }
  bool neg = dbuf.peek() & HPACK::Q_DELTA_BASE_NEG;
  err_ = dbuf.decodeInteger(HPACK::Q_DELTA_BASE.prefixLength, delta);
  if (err_ != HPACK::DecodeError::NONE) {
    LOG(ERROR) << "Decode error decoding delta base=" << err_;
    return 0;
  }
  if (neg) {
    // delta must be smaller than RIC
    if (delta >= requiredInsertCount) {
      LOG(ERROR) << "Received invalid delta=" << delta
                 << " requiredInsertCount=" << requiredInsertCount;
      err_ = HPACK::DecodeError::INVALID_INDEX;
      return 0;
    }
    // The largest table we support is 2^32 - 1 / 32 entries, so
    // requiredInsertCount (less any delta, etc) must be < 2^32.
    CHECK_LE(requiredInsertCount - delta - 1,
             std::numeric_limits<uint32_t>::max());
    baseIndex_ = requiredInsertCount - delta - 1;
  } else {
    // base must be < 2^32
    if (delta > std::numeric_limits<uint32_t>::max() ||
        requiredInsertCount >=
            uint64_t(std::numeric_limits<uint32_t>::max()) - delta) {
      LOG(ERROR) << "Invalid delta=" << delta
                 << " requiredInsertCount=" << requiredInsertCount;
      err_ = HPACK::DecodeError::INVALID_INDEX;
      return 0;
    }
    baseIndex_ = requiredInsertCount + delta;
  }
  VLOG(5) << "Decoded baseIndex_=" << baseIndex_;
  return requiredInsertCount;
}